SCD2 recap: зачем snapshots в production
Этот модуль — про production-grade snapshots. На уровне junior вы видели snapshot как «способ сохранить историю customers». На уровне middle вопрос ставится острее: какие гарантии даёт snapshot, где он ломается под нагрузкой, как ведут себя ключевые конфиги в dbt 1.9+ (hard_deletes, dbt_valid_to_current, snapshot_meta_column_names) и где это всё проваливается на DuckDB.
Этот первый урок — короткий recap, чтобы выровнять словарь и зафиксировать чек-лист производственных требований к snapshot. Дальше — глубже по каждой стратегии и крайним случаям.
SCD2 в одном экране
Источник пишет текущее состояние: одна строка на сущность, любое изменение перетирает прошлое. Это эквивалент SCD Type 1 — история теряется в момент UPDATE.
Snapshot превращает Type 1 в Type 2: каждая версия записи — отдельная строка с интервалом действия.
Ключевые SCD2-колонки, которые dbt добавляет к source:
dbt_scd_id— хеш версии (unique_key + updated_at / check_cols). Используется как PK snapshot-таблицы.dbt_updated_at— когда эта версия зафиксирована.dbt_valid_from— начало периода действия (=dbt_updated_at).dbt_valid_to— конец периода.NULL(илиdbt_valid_to_current) у активной версии.
В dbt 1.9+ имена этих колонок настраиваются через snapshot_meta_column_names — пригодится при миграции из старого хранилища, где привычны другие имена (valid_from_ts, is_current_flag).
Что отличает middle от junior
На junior хватало понимать «snapshot — это история». В production добавляются нелинейные требования:
- Идемпотентность.
dbt snapshotможно перезапустить в течение одного «окна» без дублирования. Это достигается тем, что dbt сравнивает source с активными строками (dbt_valid_to IS NULL/= dbt_valid_to_current) — повторный запуск ничего не меняет, если данные не изменились. - Атомарность одного run. dbt оборачивает MERGE snapshot в транзакцию warehouse. Если посередине упало — состояние snapshot остаётся целым.
- Late-arriving изменения. Source может опоздать: вчерашнее
UPDATEпришло сегодня. Snapshot пишет «изменение зафиксировано сегодня», а не «вчера». В uri для compliance это критично — хранитеevent_timeотдельно отdbt_valid_from. - Hard deletes. Соурс может удалить строку. По умолчанию
hard_deletes: ignore— snapshot этого не заметит, останется зависшая активная строка. Это разбирается отдельным уроком. - Schema evolution. Source добавил/удалил колонку. Snapshot должен пережить это без
--full-refresh(что бы потеряло историю). - Тесты на snapshot. Snapshot — это нода dbt, поэтому к нему применяется
dbt test. На middle обязательны минимумuniqueнаdbt_scd_id,not_nullна unique_key + dbt_valid_from,not_nullнаdbt_valid_to where dbt_valid_to_current is set.
Чек-лист production snapshot
Перед тем как катить snapshot на прод, проверьте:
Эти восемь пунктов — то, что отличает «работающий snapshot» от «snapshot, на который можно опереться в compliance audit». Каждый из них раскроем глубже в следующих уроках.
Snapshot vs CDC vs audit log
Data Modeling: SCD Type 2 — теоретическая база dbt-i: первое знакомство с snapshotsЭто три разных способа «хранить историю». На middle важно понимать границы.
| Подход | Что хранит | Кто ведёт | Гранулярность | Сильные стороны | Слабости |
|---|---|---|---|---|---|
dbt snapshot | SCD2-версии по unique_key | dbt по расписанию | На момент запуска | Декларативно, дешёво, лежит в warehouse | Между запусками изменения не видны |
| CDC (Debezium, logical replication) | Каждое INSERT/UPDATE/DELETE | Source DB через WAL | На каждое изменение | Реальное время, не теряет промежуточные states | Сложная инфраструктура, требует stream-processing |
| Audit log в app | Что задумал бизнес-event | Сама aplikacija | На каждый user action | Семантика бизнес-уровня | Зависит от полноты кода, лёгко забыть писать |
dbt snapshot — это дешёвый snapshot текущего состояния через интервалы. Если бизнесу нужны все промежуточные pending -> confirmed -> paid -> refunded за заказ и интервал между ними — snapshot не подходит (он покажет только то, что было в момент его запуска). Тогда — CDC или внутренний event log в источнике.
Хорошо ли так делать в проекте? Часто комбинация: CDC из транзакционных систем для realtime фактов, snapshots для медленно меняющихся dimension-таблиц (customers, products, employees), где гранулярность раз в час / день достаточна.
DuckDB ограничения, которые отличают middle-проект от учебного
Большинство наших примеров работают на DuckDB, но три ограничения серьёзно влияют на дизайн:
hard_deletesне реализован (на dbt-duckdb 1.10.x состояние 2026 года). Любая ваша политика удалений должна обходиться через soft-delete (колонкаis_deleted) или post-hook.- Snapshot на external materialization не работает. Если source —
read_parquet('s3://...')без attached table, snapshot упадёт. Нужна локальная таблица или ATTACH к Postgres/Iceberg. - Single-writer per file. В момент
dbt snapshotваша DuckDB-база заблокирована для других writer-процессов. Если у вас несколько проектов пишут в одну.duckdb— нужно либо MotherDuck, либо разнесённые .duckdb-файлы.
В Snowflake / BigQuery / Postgres всё это решено. Дальше в курсе мы будем явно отмечать «вот тут DuckDB ведёт себя иначе» — это полезный навык для middle, потому что в реальной работе вы редко сидите на одном warehouse всю карьеру.
Попробуй сам
Откройте репозиторий dbt-ii-labs и найдите models/staging/_sources.yml. Ответьте на четыре вопроса по бизнес-логике snapshot для каждой таблицы:
- Нужен ли snapshot на эту таблицу? Если это fact (orders, events) — нет, она и так append-only. Если dimension (customers, products) — скорее всего да.
- Какая стратегия? Если в source стабильный
updated_at— timestamp. Если нет — check, и какие колонки вcheck_cols. - Что в unique_key? Стабильный PK, не атрибут.
- Какая политика hard_deletes? Допустимо ли терять deleted rows? Если нет — soft-delete pattern или переход на Postgres/Snowflake.
Зафиксируйте ответы как комментарии в YAML. Эти ответы — основа всех следующих уроков модуля.
Ключевые выводы
- SCD2 = слайс на момент через
dbt_valid_from/dbt_valid_to. Активная строка —valid_to IS NULLили= dbt_valid_to_currentsentinel. - Production snapshot требует не только конфига, но и schedule, тестов, документации, DR-плана.
- Snapshot — не CDC и не audit log: фиксирует состояние на момент запуска, между запусками изменения теряются.
- На DuckDB важны три ограничения: нет
hard_deletes, snapshot не работает на external materialization, single-writer per file. - dbt 1.9+ привнёс
hard_deletes,dbt_valid_to_current,snapshot_meta_column_names, YAML-синтаксис — это базис production-уровня, который мы дальше разбираем.