Snapshots: история изменений (SCD type 2)
Источник хранит только текущее состояние строки — snapshot запоминает, как оно менялось во времени.
Snapshot — механизм dbt, реализующий SCD type 2: при каждом запуске он сравнивает источник с сохранённой историей и фиксирует изменившиеся строки с интервалами их действия (с какого по какое время версия была актуальной).
Проблема исчезающей истории
В таблице клиентов поле status сегодня active, завтра churned. Источник просто перезапишет значение — и вы навсегда потеряете информацию, когда клиент ушёл. А бизнесу нужно отвечать на вопросы «сколько клиентов было активно в марте?», «какой тариф был у клиента в момент покупки?». Для этого нужна история — её и сохраняет snapshot.
SCD type 2: версии строк
Slowly Changing Dimension type 2 — классический приём хранилищ: вместо перезаписи строки заводят новую версию, а старую закрывают, проставив интервал действия. Так у одной сущности появляется история версий.
customer_id | status | dbt_valid_from | dbt_valid_to
42 | active | 2026-01-01 | 2026-03-15 <- старая версия (закрыта)
42 | churned | 2026-03-15 | NULL <- текущая (valid_to = NULL)
Строка с dbt_valid_to = NULL — актуальная. По интервалам можно «отмотать» состояние на любую дату.
Объявление snapshot
-- snapshots/customers_snapshot.sql
{% snapshot customers_snapshot %}
{{ config(
target_schema='snapshots',
unique_key='customer_id',
strategy='timestamp',
updated_at='updated_at'
) }}
select * from {{ source('raw', 'customers') }}
{% endsnapshot %}
unique_key | как опознать ту же сущность между запусками |
strategy='timestamp' | изменение определяется по полю времени |
updated_at | поле, по которому видно, что строка изменилась |
Альтернативная стратегия — check: dbt сам сравнивает указанные колонки, если в источнике нет надёжного updated_at.
Запуск
# Снять очередной снимок (зафиксировать изменения)
dbt snapshot
Snapshot запускают регулярно. Каждый запуск ловит то, что изменилось с прошлого раза, — поэтому важно не пропускать запуски, иначе промежуточные состояния потеряются.
Как работает под капотом
При запуске dbt берёт текущий источник и сравнивает с таблицей snapshot по unique_key. Если строка новая — вставляет с valid_from = now, valid_to = NULL. Если существующая строка изменилась (по timestamp или check) — у старой версии проставляет valid_to = now (закрывает интервал) и вставляет новую версию. Неизменившиеся строки не трогает. Так в таблице накапливается полная история, а служебные поля dbt_valid_from/to задают временные интервалы.
Частые ошибки
- Запускать snapshot редко/нерегулярно. Изменения между запусками теряются — snapshot ловит только разницу с прошлым снимком.
- Неверный
unique_key. Если ключ не опознаёт сущность, история «склеится» или раздробится. - Использовать snapshot для того, что должно быть моделью. Snapshot — про историю изменений, а не про трансформацию.
Итоги
- Snapshot реализует SCD type 2: сохраняет историю версий строк с интервалами
dbt_valid_from/to. - Стратегия
timestampилиcheckопределяет, как dbt замечает изменения. - Запускать регулярно: snapshot ловит лишь разницу с прошлым снимком.