DuckDB для аналитика: OLAP прямо в Python

Что такое DuckDB

DuckDB — это встраиваемая аналитическая БД. Можно представить её как SQLite для аналитики. Не нужен сервер, не нужно настраивать кластер — поставили пакет, импортировали в Python, написали SQL-запрос. База живёт прямо в процессе приложения.

Под капотом DuckDB — колоночное хранение (как ClickHouse), vectorized execution, современный оптимизатор запросов. По скорости на аналитических задачах она сопоставима с serverless ClickHouse, но запускается за миллисекунды и не требует ничего, кроме pip install duckdb.

Для аналитика это идеальный инструмент для локальной работы с большими файлами. Нужно прогонять SQL по parquet на 5 GB — DuckDB справится на ноутбуке, pandas в такой объём не влезет.

Установка и первый запрос

pip install duckdb
import duckdb

# Прямой запрос без создания файла-БД
result = duckdb.sql("SELECT 42 AS answer")
result.show()

DuckDB умеет работать в режиме in-memory (данные живут в RAM, не сохраняются) или с persistent файлом:

# Persistent
con = duckdb.connect('analytics.duckdb')
con.execute("CREATE TABLE orders (id INT, amount NUMERIC)")
con.execute("INSERT INTO orders VALUES (1, 100), (2, 200)")
con.close()

# In-memory (default)
con = duckdb.connect(':memory:')

Работа с CSV

Одна из killer-фич DuckDB — читать файлы напрямую из SQL, без импорта:

duckdb.sql("""
SELECT
    category,
    SUM(amount) AS revenue,
    COUNT(*) AS orders
FROM 'orders.csv'
WHERE status = 'paid'
GROUP BY category
ORDER BY revenue DESC
""").show()

Прямо в FROM указан путь к файлу. DuckDB сам парсит CSV, определяет типы, выполняет запрос. Работает с gzip-сжатием, может читать несколько файлов по wildcard:

duckdb.sql("SELECT * FROM 'logs/*.csv'")

Parquet — главная сила

Parquet — колоночный формат, идеально подходит DuckDB. Запросы на parquet в несколько раз быстрее CSV и эффективнее по памяти:

# Чтение 10 GB parquet за секунды
duckdb.sql("""
SELECT date, SUM(amount)
FROM 'year_data/*.parquet'
WHERE date >= '2026-01-01'
GROUP BY date
""").show()

DuckDB использует partition pruning (читает только нужные файлы) и projection pushdown (читает только нужные колонки). Для data lake pattern это критично.

Интеграция с pandas

DuckDB может напрямую запрашивать pandas DataFrames:

import pandas as pd
import duckdb

orders = pd.read_csv('orders.csv')
products = pd.read_csv('products.csv')

# SQL прямо на pandas dataframes
result = duckdb.sql("""
SELECT
    p.category,
    SUM(o.amount) AS revenue
FROM orders o
JOIN products p ON p.product_id = o.product_id
GROUP BY p.category
""").to_df()

Это меняет подход к pandas-работе. Сложные JOIN-ы и GROUP BY писать в SQL проще и быстрее, чем через методы pandas. А конвертации между типами данных бесплатны — DuckDB и pandas используют Apache Arrow под капотом.

Разобраться с современным Python-стеком — важная часть middle+ подготовки. В тренажёре Карьерник есть задачи на SQL и Python для аналитики с разборами инструментов.

Типичные сценарии

Быстрый анализ большого файла

CSV или parquet на несколько GB. pandas падает по памяти, полноценную БД разворачивать не хочется. DuckDB — идеальное решение:

import duckdb

# Один раз прогнать тяжёлую агрегацию
summary = duckdb.sql("""
SELECT
    DATE_TRUNC('day', event_time) AS day,
    COUNT(DISTINCT user_id) AS dau,
    COUNT(*) AS events
FROM 'huge_events.parquet'
WHERE event_time >= '2026-01-01'
GROUP BY 1
ORDER BY 1
""").to_df()

Теперь summary — маленький DataFrame на 100 строк. Дальше работаете с ним как обычно.

ETL-скрипты

Вместо громоздких цепочек pandas-операций — чистый SQL:

duckdb.sql("""
COPY (
    SELECT
        user_id,
        SUM(amount) AS total,
        COUNT(*) AS orders,
        MIN(created_at) AS first_order,
        MAX(created_at) AS last_order
    FROM 'raw_orders.parquet'
    WHERE status = 'paid'
    GROUP BY user_id
) TO 'user_summary.parquet' (FORMAT PARQUET)
""")

Читаем raw, агрегируем, сохраняем в новый parquet. Одна команда, запускается за секунды на миллионах строк.

Присоединение внешних источников

DuckDB умеет запрашивать удалённые файлы — S3, HTTP, Google Cloud Storage:

duckdb.sql("""
SELECT COUNT(*)
FROM 's3://my-bucket/events/2026/*.parquet'
""")

Для этого нужны credentials. DuckDB поддерживает httpfs-extension для работы с remote storage.

Удобный SQL на ноутбуке

Jupyter + DuckDB даёт удобный инструмент для ad-hoc анализа:

import duckdb
import pandas as pd

# Подключаемся к persistent базе
con = duckdb.connect('analytics.duckdb')

# Вопросы аналитика — на SQL, быстро
con.sql("""
    WITH monthly AS (
        SELECT DATE_TRUNC('month', created_at) AS month,
               COUNT(*) AS orders
        FROM orders GROUP BY 1
    )
    SELECT * FROM monthly ORDER BY month DESC
""").show()

DuckDB vs SQLite

SQLite тоже встраиваемая БД, но для OLTP (единичные записи, транзакции). DuckDB для OLAP (аналитика, агрегаты). На аналитических задачах DuckDB в 10-100 раз быстрее SQLite.

Если ваша задача — хранить настройки приложения или небольшие связанные данные, SQLite. Если считать метрики по большому CSV — DuckDB.

DuckDB vs ClickHouse

ClickHouse — distributed, серверный, для production analytics с большими объёмами. DuckDB — локальный, embedded.

В какой-то мере это spectrum:

DuckDB — для разработки, ad-hoc, небольших dashboards. Запускается за миллисекунды.

ClickHouse — для production, множественных пользователей, объёмов в терабайты.

Они дополняют друг друга. Можно тестировать логику на DuckDB локально, потом переносить в ClickHouse для production.

dbt-duckdb

Интересно: для DuckDB есть dbt-адаптер. Это позволяет писать dbt-модели, выполняемые локально на DuckDB — идеально для тестирования моделей без production-среды.

pip install dbt-duckdb

Настройка profile:

my_project:
  target: local
  outputs:
    local:
      type: duckdb
      path: ./analytics.duckdb

Локальная среда для dbt development — удобно.

Ограничения

Не для multi-user production. DuckDB предполагает одного пользователя или процесса. Для real-time аналитики с тысячами запросов — ClickHouse или Snowflake.

Ограниченная поддержка UPDATE/DELETE. DuckDB оптимизирован для аналитических чтений. OLTP-операции работают, но не так эффективно.

Нет distributed вычислений. Один сервер, одна машина. Для петабайтов нужны специализированные решения.

Производительность

На 10 GB parquet-файле — пример бенчмарка (приблизительно):

  • SELECT COUNT(DISTINCT user_id) — 1.2 секунды.
  • GROUP BY category SUM(amount) — 0.8 секунды.
  • JOIN 10M × 1M — 2.5 секунды.

Для сравнения — pandas на том же датасете падает по памяти или работает минуты.

Когда стоит попробовать

Если в вашей работе:

Часто приходят parquet/csv файлы на гигабайты, которые нужно быстро анализировать.

Используете pandas, но встречаете лимиты по памяти.

Хочется SQL для ad-hoc анализа без запуска отдельной БД.

Нужен быстрый способ тестировать dbt-модели локально.

Один недельный эксперимент даст понять, подходит ли.

Читайте также

FAQ

DuckDB бесплатный?

Да, MIT license. Можно использовать в коммерческих проектах без ограничений.

На production годится?

Для embedded сценариев (локальный анализ, dbt-тесты) — да. Для multi-user web app — нет, нужна полноценная БД.

С JSON работает?

Да, поддерживает JSON типы и функции, похоже на PostgreSQL JSONB.

Можно ли в Rust/Go/Java?

Да, биндинги есть для всех популярных языков. В Python самый развитый API.