Понимание инкрементальных стратегий dbt, часть 1

Перевод статьи, исходный текст: https://medium.com/indiciumtech/understanding-dbt-incremental-strategies-part-1-2-22bd97c7eeb5

Данный перевод выполнен с небольшими примечаниями. Используйте статью как ориентир, проверяя по каждой базе и каждому адаптеру возможность реализации. Особенно это касается партиций. Перевод выполнен 1 в 1 без удаления реплик автора.

С технической точки зрения я не везде согласен с автором, оценил бы статью на 3 из 5, но с другой стороны общее представление по инкрементальным стратегиям можно получить. 

Плюс в конце статьи еще есть подборка видео с YouTube на english.


Понимание инкрементальных стратегий dbt, часть 1/2

В этой статье я расскажу об инкрементальных стратегиях в dbt, о том, как они работают, а также о плюсах и минусах каждой из них. В следующей статье я объясню, как на практике реализовать инкрементальные стратегии в ваших моделях.

Используя инкрементальные модели, вы можете преобразовывать и добавлять в таблицы только недавние данные, значительно сокращая (в зависимости от размера таблицы) затраты на обработку и время выполнения. Однако, прежде чем углубляться в эту тему, вам нужно задать себе вопрос: действительно ли вам нужно использовать инкрементальные модели?

Инкрементальная материализация — это продвинутая и мощная функция dbt, но ее не нужно применять в каждой модели проекта. Есть несколько моментов, которые следует учитывать, чтобы не изменять конфигурацию модели и не добавлять множество условий Jinja без необходимости.

Стоит ли использовать инкрементальную модель?

Как я упомянул в начале, инкрементальные модели не нужны для каждой модели. Во многих случаях стратегия полного обновления (full refresh) может быть лучшим вариантом, поэтому давайте подробнее обсудим этот подход.

Стратегия полного обновления (full refresh)

Полное обновление — это стандартный и наиболее распространенный процесс преобразования данных в вашем хранилище данных (DW). Если вы не укажете материализацию как инкрементальную, ваша таблица будет полностью пересоздана при каждом запуске.

Предположим, у нас есть исходная таблица с данными до 2022-02-02, и мы хотим обновить целевую таблицу, содержащую данные до 2022-01-04. При использовании стратегии полного обновления dbt сначала удалит текущую целевую таблицу (1), а затем создаст новую таблицу из преобразованных исходных данных (2).

Рисунок 1 — Пример полного обновления

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

Во-первых, в режиме полного обновления существует четкий компромисс между сложностью и затратами/временем обработки. Это низкосложный процесс: вам не нужно беспокоиться о настройке инкрементальных правил, и вы можете быть уверены, что целевая таблица получит все преобразованные данные.

С другой стороны, полное обновление требует больше времени и средств на пересоздание всей таблицы. Если ваша таблица небольшая, скажем, несколько миллионов строк или меньше, преобразования не являются затратными, и вы не беспокоитесь о затратах и времени, то можно использовать полное обновление.

Что касается частоты изменения данных, если данные в модели меняются редко, инкрементальные стратегии не дадут вам особого преимущества — вы можете просто выполнять периодические полные обновления. А если исторические данные модели часто изменяются, инкрементальные стратегии не смогут это учесть, так как они ориентированы на недавние данные, и полное обновление может быть более подходящим вариантом.

С точки зрения низкой сложности и практического использования, полное обновление может быть полезным для быстрого предоставления целевой таблицы конечному пользователю, что позволяет создавать ценность как можно быстрее. Таким образом, конечный пользователь может проверить преобразование и дать обратную связь, попросив о изменениях или исправлениях. Кроме того, наличие преобразованной таблицы в продакшене дает аналитическому инженеру лучшее понимание базы данных: как часто обновляются данные и какой объем данных обрабатывается при каждом запуске. Эти аспекты важны для оптимизации модели.

На этапе оптимизации можно оценить стратегии по сокращению затрат, объема обработки или времени выполнения, например, удалив столбцы, которые не создают ценности, или изменив материализацию модели.

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

Основные преимущества:

  • Простота реализации
  • Быстрое создание ценности
  • Гарантия того, что все данные будут добавлены в целевую таблицу, независимо от правил обновления БД

Основные недостатки:

  • Высокие затраты на обработку
  • Длительное время обработки

Когда использовать:

  • Когда вам не нужно беспокоиться о затратах и времени (для небольших таблиц или таблиц с простыми преобразованиями)
  • Когда данные более статичны, чем динамичны
  • Когда исторические данные часто изменяются

Но если вам нужно сократить затраты, ускорить преобразования или если ваша таблица часто получает новые данные, и вы уверенно пользуетесь dbt, вам стоит попробовать инкрементальные модели.

Если вы новичок в dbt или плохо знаете команды dbt, ознакомьтесь с моей статьей о командах dbt: 17 dbt Commands You Should Start Using Today.

Инкрементальные модели

Инкрементальная материализация направлена на сокращение времени и затрат на обработку, преобразовывая и добавляя только более свежие данные.

Чтобы dbt знал, какие данные являются недавними, в вашей таблице должен быть столбец одного из следующих типов: date, datetime, timestamp или int64. Модель будет использовать столбцы исходной и целевой таблиц для фильтрации данных, которые нужно преобразовать, добавить, обновить или удалить.

Очень важно помнить, что инкрементальные стратегии не учитывают изменения, внесенные в старые записи. Поэтому хорошей практикой является периодическое выполнение полного обновления таблицы для актуализации исторических данных.

Также важно отметить, что ваша таблица будет обрабатываться инкрементально, если выполняются три условия:

  1. целевая таблица уже существует в базе данных,
  2. dbt не запускается в режиме полного обновления (вы не используете флаг --full-refresh), и
  3. текущая модель настроена с materialized='incremental'.

dbt предлагает четыре типа инкрементальных стратегий:

  • append
  • merge
  • delete+insert
  • insert_overwrite

Доступность стратегии зависит от используемого адаптера. В документации dbt перечислены три адаптера и их соответствующие стратегии:

  • Snowflake: merge (по умолчанию), delete+insert (опционально)
  • BigQuery: merge (по умолчанию), insert_overwrite (опционально)
  • Spark: append (по умолчанию), insert_overwrite (опционально), merge (опционально, только для Delta)

Давайте рассмотрим каждую из них.

Append

Стратегия append (добавление) очень проста: она просто берет выбранные записи и вставляет их в целевую таблицу. Она не может обновлять или удалять записи, только вставлять. Вы можете использовать эту стратегию только в том случае, если дубликаты не являются для вас проблемой. Append не заботится о дубликатах: она не проверяет, существует ли запись уже в целевой таблице, а просто вставляет дублированные записи.

Примечание от datatalks.ru: можно вставлять только новые строки, проверяя наличие в таблице. Но, возможно, в стандартных стратегиях appends в адаптерах не реализована проверка наличия строк. Или, например, отсутстует anti join и его можно реализовать, например, через LEFT JOIN с условием IS NULL.

Например, предположим, что у нас есть те же таблицы, что и в примере с полным обновлением. Если мы выберем записи за сегодня и вчера (1), допустим, сегодня 2022-02-02. Строки будут вставлены в целевую таблицу (2), и мы получим 2 дублированные строки.

Рисунок 2 — Пример Append

Ключевые моменты append:

Основные преимущества:

  • Простота и понятность
  • Низкие затраты на обработку, так как не требуется сканирование целевой таблицы
  • Низкое время обработки

Основные недостатки:

  • Невозможно обновлять или удалять строки, только вставлять
  • Дубликаты! (примечание от datatalks.ru: нужно их обрабатывать с помощью Anti Join)

Когда использовать:

  • Когда вы работаете с таблицами только для добавления записей (append-only)
  • Когда вас не беспокоят дубликаты
  • Когда требуется только добавление новых строк

Merge

Стратегия merge решает проблему дублированных записей. Она может обрабатывать дубликаты, если вы укажете уникальный ключ (который может состоять из одного или нескольких столбцов). Если уникальный ключ уже существует в целевой таблице, merge обновит запись, поэтому дубликатов не будет. Если записи не существуют, merge добавит их.

Чтобы проверить совпадение уникальных ключей в обеих таблицах, merge должен сканировать всю целевую таблицу, а также выбранную часть исходной таблицы. Это полное сканирование делает стратегию довольно затратной.

Если вы используете merge без указания уникального ключа, это фактически то же самое, что append. Однако, например, в BigQuery использование уникального ключа с merge является обязательным.

Рисунок 3 — Пример Merge

Вернемся к нашему примеру. Предположим, сегодня 2022-02-02, и мы хотим объединить записи за сегодня и вчера с помощью merge.

Dbt сначала получает выбранные записи, указанные в операторе where (1). Затем выполняет сканирование (2), и если записи существуют в целевой таблице, они обновляются; если их нет, они добавляются (3).

Чтобы повысить производительность merge и сократить затраты, целевую таблицу можно кластеризовать. Таким образом, не потребуется полное сканирование целевой таблицы.

Рисунок 4 — Пример кластеризации для Merge

Ключевые моменты merge:

Основные преимущества:

  • Устраняет дубликаты
  • Хорошо работает для небольших таблиц (менее нескольких миллионов строк)

Основные недостатки:

  • Высокие затраты на обработку из-за необходимости полного сканирования целевой таблицы

Когда использовать:

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

Delete+Insert

Стратегия delete+insert очень похожа на merge, но вместо обновления существующих записей и добавления новых она удаляет существующие записи и вставляет как новые, так и уже существующие записи. Поскольку она удаляет существующие записи из целевой таблицы, дубликаты также отсутствуют.

Рисунок 5 — Пример стратегии Delete+insert

(Да, я знаю, что использую этот пример на протяжении всей статьи :), но, на мой взгляд, так легче объяснить.)

При использовании delete+insert dbt сначала получает выбранные записи (1), выполняет их сканирование и полное сканирование целевой таблицы для сравнения уникальных ключей (2). Затем удаляет (3) существующие записи и вставляет выбранные (4).

Я не могу рассказать много подробностей об этой стратегии, так как не нашел достаточной документации или каких-либо бенчмарков, связанных с ее использованием. Однако, вероятно, она будет дорогостоящей из-за полного сканирования.

Insert Overwrite

Последняя инкрементальная стратегия, о которой я расскажу, — это insert overwrite. Эта стратегия решает проблему полного сканирования. Решение, используемое в insert overwrite, заключается в работе с разделами (partitions).

Разделение таблицы на части означает ее деление на сегменты. Для работы insert overwrite раздел может быть следующих типов:

  • date,
  • datetime, timestamp, (примечание от datatalks.ru: скорей всего нельзя, слишком много значений будет)
  • int64.

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

Стратегия insert overwrite удаляет выбранные разделы из текущей целевой таблицы и вставляет в нее выбранные преобразованные разделы.

Рисунок 6 — Пример стратегии Insert Overwrite

В приведенном выше примере целевая таблица разделена по дням (для повышения производительности исходная таблица также может быть разделена). Необходимо указать, какие разделы будут заменены в целевой таблице, и они определяются параметром конфигурации под названием partitions (мы рассмотрим это подробнее в следующей статье). В этом примере мы хотим заменить разделы за сегодня и вчера, предположим, что сегодня 2022-02-02.

Мы можем использовать оператор where в модели, указав, что нас интересуют записи, даты которых входят в параметр partitions. Таким образом, будут выбраны записи за сегодня и вчера (1).

Затем в целевой таблице находятся и удаляются соответствующие разделы как часть оператора merge (2). Так как таблица разделена, полное сканирование не требуется. Это основное отличие между insert overwrite и merge, что значительно сокращает объем обрабатываемых данных.

Наконец, выбранные записи вставляются в целевую таблицу как часть оператора merge (3).

За исключением использования разделов, этот процесс похож на стратегию delete+insert. Однако стратегия delete+insert использует два отдельных оператора — delete и insert, а insert overwrite использует оператор merge с постоянным ложным предикатом.

Insert overwrite — это стратегия высокой сложности. Если ее неправильно настроить, она может приводить к дублированию данных. Например, представим таблицу сотрудников, и мы используем стратегию insert overwrite на основе столбца updated_at.

Рисунок 7 — Проблемы с Insert Overwrite

Если через месяц запись сотрудника 1 будет обновлена, эта запись снова будет вставлена в целевую таблицу. Периодическое полное обновление решает эту проблему, но если вы не можете ждать выполнения полного обновления, следует использовать другой столбец или рассмотреть стратегию merge.

Основные моменты Insert Overwrite:

Основные преимущества:

  • Низкие затраты на обработку
  • Низкое время обработки

Основные недостатки:

  • Высокая сложность
  • Может привести к дублированию данных, если неправильно настроено

Когда использовать:

  • Когда вы работаете с большими динамическими наборами данных
  • Когда затраты и время обработки становятся проблемой

Сравнение стратегий

Вот сравнение различных стратегий. Delete+insert не включена, так как я не нашел достаточно информации о ней. Более детальный бенчмарк инкрементальных стратегий вы можете найти по ссылке.

Рисунок 8 — Сравнение стратегий

 
Дерево решений, которое поможет вам выбрать наиболее оптимальную реализацию:
 

Заключение

Это конец первой части статьи о инкрементальных стратегиях в dbt. Теперь вы должны лучше понимать, когда использовать инкрементальные стратегии, а когда — нет. Кроме того, вы узнали, как работают различные стратегии и в каких случаях их применять.

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

Надеюсь, вам понравилась эта статья! Лучший способ изучить что-то — попытаться объяснить это кому-то другому, и это то, что я пытаюсь сделать. Оставляйте комментарии, если у вас есть вопросы, предложения или даже исправления к тексту!

=== Конец перевода 🙂 ===

Вторую статью можно почитать по ссылке (юзать сами знаете что): Understanding dbt Incremental Strategies part 2/2

Ознакомьтесь с официальной документацией по инкрементальным моделям:

Дополнение к статье YouTube (как смотреть разберетесь, надеюсь)

Merge Tables With Incremental Models | dbt Tutorial

YouTube — dbt Tutorial: dbt incremental models in bigquery; MERGE vs. INSERT_OVERWRITE

Dbt Materializations — Incremental Snapshot | data build tool | Slowly Changing Dimension SCD Type 2

Incremental Models (Faisal El Shami)

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x