# Отслеживание изменений данных в dbt

Отслеживание изменений данных (Change data capture, CDC) позволяет выявлять новые, изменённые и удалённые строки в исходных данных, чтобы обрабатывать изменения без перестроения *всей* таблицы.

В этом руководстве объясняется, как использовать инкрементальные модели и снимки в dbt, чтобы поддерживать таблицы в актуальном состоянии, сохранять историю изменений или решать обе задачи. Чтобы выбрать оптимальный подход для своего проекта, обратитесь к разделу [Выбор инкрементальных моделей или снимков](https://docs.getdbt.tech/best-practices/how-we-handle-cdc/2-choosing-incremental-or-snapshots.md). Информацию о частоте запуска заданий, потоках и динамических таблицах см. в разделе [Данные в dbt в режиме, близком к реальному времени](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/1-intro.md), в том числе в подразделе [CDC с помощью Snowflake Streams](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/2-incremental-patterns.md#cdc-with-snowflake-streams).

## Как работать с CDC в dbt

Когда исходные данные меняются, вам может потребоваться обновить таблицу, сохранить старые версии или сделать и то и другое.

В dbt для этого обычно используется один из двух способов построения таблицы:

* [Инкрементальная модель](https://docs.getdbt.tech/docs/build/incremental-models-overview.md) поддерживает таблицу в актуальном состоянии. При каждом запуске dbt обрабатывает новые или изменённые строки и *заменяет* старую строку с соответствующим значением `unique_key`.
* [Снимок](https://docs.getdbt.tech/docs/build/snapshots.md) сохраняет историю. При каждом запуске dbt сравнивает исходные данные с последним снимком и *добавляет* строку при изменении записи, указывая `dbt_valid_from` и `dbt_valid_to`.

Снимки фиксируют изменения только при запуске, поэтому их следует запускать по расписанию, иначе вы можете пропустить изменения. Обратитесь к ответу на частый вопрос [Как часто следует запускать команду snapshot?](https://docs.getdbt.tech/faqs/Runs/snapshot-frequency.md), где рекомендуется запускать её с периодичностью от одного раза в час до одного раза в день.

## Выберите подход: последняя версия строки, история или и то и другое

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

| Что вам нужно                                                                        | Как источник хранит изменения                                                                                  | Что использовать                                                                                                                                 |
| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Только последняя версия строки                                                       | Добавляет строку для каждого изменения или перезаписывает строки, но содержит надёжную метку времени изменения | Инкрементальная модель                                                                                                                           |
| Текущая строка и старые версии                                                       | Перезаписывает строки и достаточно мал, чтобы сканировать его при каждом запуске                               | Снимок                                                                                                                                           |
| Текущая строка и старые версии без полного сканирования источника при каждом запуске | Перезаписывает строки или добавляет строку для каждого изменения (после очистки данных)                        | Инкрементальная модель промежуточного слоя (staging), затем снимок, затем зависимая модель, сохраняющая только последнюю версию строки из снимка |

<br />

Примеры каждого подхода см. в разделе [Выбор инкрементальных моделей или снимков](https://docs.getdbt.tech/best-practices/how-we-handle-cdc/2-choosing-incremental-or-snapshots.md).

## Основные рекомендации

* Используйте инкрементальные модели, если вам нужны только текущие строки и вы можете выявлять новые или изменённые строки. Инкрементальная модель *заменяет* старую строку, поэтому объём обработки при каждом запуске остаётся небольшим, а версии, к которым вы никогда не будете обращаться в запросах, не хранятся.
* Используйте снимки, если вам нужно знать, как выглядела запись в определённый момент в прошлом. Снимок *добавляет* строку при изменении записи, благодаря чему сохраняется старая версия. Инкрементальная модель перезаписала бы её.
* Используйте оба подхода, если промежуточный слой должен оставаться актуальным при небольших затратах на обработку, а снимок должен хранить версии. Инкрементальная модель ограничивает объём обрабатываемых данных. Снимок сохраняет историю. Создавайте снимки моделей промежуточного слоя (или источников), а не итоговой таблицы, к которой обращаются пользователи: так вы будете отслеживать изменения источника, а не отчёта, который может меняться по другим причинам.
* Отдавайте предпочтение стратегии снимков `timestamp`, если поле `updated_at` надёжно и его значение только увеличивается. Это позволяет dbt выявлять изменения по метке времени, а не сравнивать каждый столбец. Используйте `check`, если метка времени отсутствует или ненадёжна, чтобы изменения строки всё равно фиксировались.
* Если хранилище уже записывает список изменений (потоки), используйте инкрементальную модель. Хранилище уже выявило изменение, поэтому для его обнаружения снимок не нужен. Соответствующий пример см. в разделе [CDC с помощью Snowflake Streams](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/2-incremental-patterns.md#cdc-with-snowflake-streams).
