Частая история: данные приложения попадают куда-то, джоб их чистит, Postgres хранит их «для аналитики» и вдруг вы обслуживаете ETL-пайплайн и базу данных, которая никогда не была рада OLAP-нагрузке. По моему мнению, для большинства команд это лишние сложности.
Главная сила DuckDB не в том, что он быстрый (хотя это правда). Она в том, что он может работать как микро-хранилище: один .duckdb-файл, который ведёт себя как аккуратный аналитический движок, находится рядом с данными и обеспечивает дашборды, аудиты и еженедельные отчёты без платформенного оверхеда.
Концепция микро-хранилища
Классический warehouse-стек предполагает, что вы решаете задачи:
-
много одновременных пользователей,
-
общее управление данными,
-
долгоживущие пайплайны,
-
несколько доменов, питающих одну каноническую модель.
Микро-хранилище предполагает нечто меньшее и более честное:
-
одна команда владеет им,
-
несколько «золотых» таблиц и вьюх имеют значение,
-
свежесть данных важнее совершенства,
-
реальный продукт — надёжные ответы.
DuckDB идеально вписывается во второй мир, потому что это встроенная аналитическая база данных, которая умеет читать локальные файлы (Parquet/CSV/JSON), удалённые объектные хранилища и даже другие базы данных — без превращения стека в распределённый научный проект.
Почему «ETL + Postgres» ломается (и тихо сжигает недели)
Postgres — отличный инструмент. Но его использование как основного аналитического движка превращается в смерть от тысячи мелких порезов.
OLAP-проблемы накапливаются как «мелочи»
Добавляешь индексы, потом ещё, потом vacuum становится ритуалом. Запросы недельных когорт конкурируют с транзакционной нагрузкой. Все начинают просить преагрегированные таблицы, потому что «дашборд тормозит». ETL-джобы сцепляются с правками схемы и разовыми фиксами.
Ничего из этого не взрывается в первый день. Это просто постепенно превращает команду в штатных администраторов базы данных.
Предложение DuckDB прямолинейно: перестань строить мини-платформу данных, когда тебе был нужен просто чистый аналитический слой.
Архитектура: один файл, один движок, меньше точек отказа
Вот форма микро-хранилища, которая работает в реальных командах:
[БД приложения / события] [Файлы в S3/GCS] [CSV вручную] | | | | (разовая выгрузка) | (запрос напрямую) | (разовая загрузка) v v v (снапшот по расписанию) внешние таблицы/вьюхи staging-таблицы \ / / \ / / v v v +---------------------------+ | DuckDB-файл | | bronze -> silver -> gold | +---------------------------+ | | (экспорты, BI, API) v дашборды / отчёты
DuckDB становится «истинным» аналитическим слоем, но система остаётся лёгкой. «Пайплайн» обычно это:
-
скрипт обновления по расписанию,
-
несколько вьюх,
-
воспроизводимый экспорт.
И да, с реальным SLA.
Неожиданно чистый SLA, который можно предложить
Шаблон практического SLA
-
Свежесть: «Данные обновляются каждые 15 минут (или раз в час), временная метка последнего успешного обновления логируется.»
-
Корректность: «Золотые метрики определены в версионируемых SQL-вьюхах; изменения проходят ревью.»
-
Производительность: «Дашборды p95 < 2с для стандартных фильтров за последние 90 дней.»
-
Восстановление: «При сбое обновления можно пересобрать из Parquet-снапшотов менее чем за 30 минут.»
-
Стоимость/ops: «Нет постоянно работающего хранилища. Один джоб по расписанию плюс один файл.»
Вот где важен «один файл»: ваше хранилище — не кластер, который вы дебажите в 2 ночи. Это артефакт, который можно бэкапить, копировать и воспроизводить.
Реальный паттерн: продуктовая аналитика без платформенного налога
Типичная ситуация — B2B SaaS-команда:
-
нужны еженедельно активные команды, adoption фич, когорты удержания,
-
события в реляционной БД, логи в объектном хранилище,
-
«хранилище» сейчас — ETL + Postgres + дашборды,
-
команда маленькая, вопросы стабильные, стек тяжёлый.
С DuckDB это выглядит так:
-
Ежедневный снапшот ключевых таблиц в Parquet.
-
События как Parquet, разбитый по дате.
-
Золотые метрики как вьюхи в DuckDB.
-
Выгрузка curated-таблиц обратно в Parquet для BI-инструментов.
DuckDB читает Parquet напрямую, в том числе несколько файлов как одну логическую таблицу.
Если данные лежат в S3-совместимом объектном хранилище, расширение httpfs поддерживает удалённый доступ к файлам, включая S3 API.
Рабочие сниппеты: джоб обновления и «золотой» слой
1. Минималистичный скрипт обновления (Python)
import duckdbfrom datetime import datetimeDB = "micro_warehouse.duckdb"con = duckdb.connect(DB)# Одноразовая установка (безопасно запускать повторно в большинстве случаев)con.execute("INSTALL httpfs;")con.execute("LOAD httpfs;")# Читаем партиционированный Parquet как логическую таблицуcon.execute("""CREATE OR REPLACE VIEW bronze_events ASSELECT *FROM read_parquet('data/events/date=*/events-*.parquet');""")# Silver: типизация + очисткаcon.execute("""CREATE OR REPLACE VIEW silver_events ASSELECT CAST(event_time AS TIMESTAMP) AS event_time, user_id, team_id, event_name, NULLIF(properties, '') AS propertiesFROM bronze_eventsWHERE user_id IS NOT NULL;""")# Gold: метрики (стабильный интерфейс)con.execute("""CREATE OR REPLACE VIEW gold_weekly_active_teams ASSELECT date_trunc('week', event_time) AS week, COUNT(DISTINCT team_id) AS weekly_active_teamsFROM silver_eventsGROUP BY 1ORDER BY 1;""")# Экспортируем curated-таблицу для BIcon.execute("""COPY (SELECT * FROM gold_weekly_active_teams)TO 'exports/gold_weekly_active_teams.parquet' (FORMAT PARQUET);""")con.execute("CREATE OR REPLACE TABLE ops_refresh_log AS SELECT 1 AS dummy;")con.execute("""INSERT INTO ops_refresh_logSELECT 1""")print("Обновление OK:", datetime.utcnow().isoformat(), "DB:", DB)
Это не «платформа данных». Это надёжная процедура.
2. Инкрементальные обновления, когда они нужны
Если «золотые» таблицы нужно поддерживать инкрементально, DuckDB поддерживает MERGE — удобно для upsert в материализованную таблицу по ключу.
Схема:
-
добавляем новые сырые события,
-
пересчитываем небольшое скользящее окно,
-
MERGEв материализованную золотую таблицу по ключу(week, team_id).
Приём для миграции: оставить Postgres, но перестать злоупотреблять им
Иногда самая быстрая миграция — не жёсткое переключение, а постепенный сдвиг:
-
OLTP остаётся в Postgres,
-
OLAP-запросы переезжают в DuckDB.
У DuckDB есть расширение для Postgres, которое умеет читать и писать в работающий Postgres-инстанс — можно федерировать или мигрировать постепенно вместо переписывания всего за один уик-энд.
Для команд, которым нужны результаты в текущем спринте, это существенно.
Ограничения: когда DuckDB не подходит как хранилище
Микро-хранилище — не универсальный инструмент. Важно честно обозначить границы.
DuckDB подходит, когда:
-
аналитических пользователей немного (маленькая команда, запросы по расписанию, BI-экспорты),
-
данные преимущественно append-only или снапшот-based,
-
вы работаете с Parquet и файловыми воркфлоу,
-
нужны воспроизводимость и портируемость.
DuckDB не подходит, когда:
-
нужна высокая конкурентность с большим числом интерактивных пользователей,
-
нужны тяжёлые OLTP-записи и строгая транзакционная семантика для приложений,
-
требуется сложное управление данными с политиками на уровне строк для множества арендаторов,
-
«хранилище» — это контракт компании с десятками продюсеров.
Если вы в первом случае — вам нужна адекватность стека. Если во втором — полноценное хранилище.
Итого: меньший стек, который всё равно ощущается «настоящим»
Главное в подходе микро-хранилища — психологическое: система снова ощущается управляемой.
Один файл. Один движок. Джоб обновления, в котором можно разобраться. Метрики, определённые в SQL, который можно проревьюить. Экспорты, которые можно воспроизвести. SLA, который можно сформулировать без расплывчатых объяснений.
Если сейчас вы запускаете «ETL + Postgres» главным образом потому что это дефолт — возможно, один DuckDB-файл отделяет вас от более простой жизни.
Подписывайтесь на наш Telegram-канал. Мы делаем тренажёры и симуляторы по построению хранилищ на dbt, пайплайнов на Dagster и построению Lakehouse на Spark + Iceberg.
ссылка на оригинал статьи https://habr.com/ru/articles/1022746/