Клонирование инкрементальных моделей как первый шаг вашей CI задачи
Прежде чем начать, вы должны знать о нескольких условиях:
dbt clone
доступен только в dbt версии 1.6 и новее. Обратитесь к нашему руководству по обновлению для помощи в активации новых версий в dbt Cloud.- Эта стратегия работает только для хранилищ, поддерживающих клонирование без копирования (в противном случае
dbt clone
просто создаст указательные представления). - Некоторые команды могут захотеть протестировать, что их инкрементальные модели работают как в инкрементальном режиме, так и в режиме полного обновления.
Представьте, что вы создали Slim CI задачу в dbt Cloud, и она настроена на:
- Откладывание на ваше производственное окружение.
- Выполнение команды
dbt build --select state:modified+
для выполнения и тестирования всех моделей, которые вы изменили, и их зависимостей. - Запуск при открытии разработчиком вашей команды PR против основной ветки.
Теперь представьте, что ваш dbt проект выглядит примерно так в DAG:
Когда вы открываете pull request (PR), который изменяет dim_wizards
, ваша CI задача начнется и построит только измененные модели и их зависимости (в данном случае, dim_wizards
и fct_orders
) в временной схеме, уникальной для вашего PR.
Это построение имитирует поведение, которое произойдет после слияния PR в основную ветку. Это гарантирует, что вы не вносите критических изменений, не требуя построения всего вашего dbt проекта.
Что происходит, когда одна из измененных моделей (или одна из их зависимостей) является инкрементальной моделью?
Поскольку ваша CI задача строит измененные модели в схеме, специфичной для PR, при первом выполнении dbt build --select state:modified+
, измененная инкрементальная модель будет построена полностью, потому что она еще не существует в схеме, специфичной для PR, и is_incremental будет ложным. Вы работаете в режиме full-refresh
.
Это может быть не оптимально, потому что:
- Обычно инкрементальные модели являются вашими крупнейшими наборами данных, поэтому их полное построение занимает много времени, что может замедлить время разработки и привести к высоким затратам на хранилище.
- Существуют ситуации, когда
full-refresh
инкрементальной модели успешно проходит в вашей CI задаче, но инкрементальное построение той же таблицы в продакшене может завершиться неудачей при слиянии PR в основную ветку (например, дрейф схемы, когда конфигурация on_schema_change установлена наfail
).
Вы можете смягчить эти проблемы, клонируя без копирования соответствующие, уже существующие инкрементальные модели в схему, специфичную для PR, как первый шаг CI задачи, используя команду dbt clone
. Таким образом, инкрементальные модели уже существуют в схеме, специфичной для PR, когда вы впервые выполняете команду dbt build --select state:modified+
, и флаг is_incremental
буде т true
.
У вас будет две команды для выполнения проверки CI в dbt Cloud:
- Клонируйте все уже существующие инкрементальные модели, которые были изменены или являются зависимыми от другой измененной модели:
dbt clone --select state:modified+,config.materialized:incremental,state:old
- Постройте все модели, которые были изменены, и их зависимости:
dbt build --select state:modified+
Благодаря вашему первому шагу клонирования, инкрементальные модели, выбранные в вашем dbt build
на втором шаге, будут выполняться в инкрементальном режиме.
Ваши CI задачи будут выполняться быстрее, и вы более точно имитируете поведение, которое произойдет после слияния PR в основную ветку.
Расширение на тему "думайте о дрейфе схемы", когда конфигурация on_schema_change установлена на fail
Представьте, что у вас есть инкрементальная модель my_incremental_model
с следующей конфигурацией:
{{
config(
materialized='incremental',
unique_key='unique_id',
on_schema_change='fail'
)
}}
Теперь, допустим, вы открываете PR, который добавляет новый столбец в my_incremental_model
. В этом случае:
- Инкрементальное построение завершится неудачей.
full-refresh
будет успешным.
Если у вас есть ежедневная производственная задача, которая просто выполняет dbt build
без флага --full-refresh
, после слияния PR в основную ветку и запуска задачи, вы получите ошибку. Итак, вопрос - что вы хотите, чтобы произошло в CI?
- Хотите ли вы также получить ошибку в CI, чтобы знать, что после слияния этого PR в основную ветку вам нужно немедленно выполнить
dbt build --full-refresh --select my_incremental_model
в продакшене, чтобы избежать ошибки в продакшене? Это заблокирует прохождение вашей проверки CI. - Хотите ли вы, чтобы ваша проверка CI прошла успешно, потому что после выполнения
full-refresh
для этой модели в продакшене вы будете в успешном состоянии? Это может привести к неприятным сюрпризам, если ваша производственная задача внезапно начнет давать сбой при слиянии этого PR в основную ветку, если вы не помните, что вам нужно выполнитьdbt build --full-refresh --select my_incremental_model
в продакшене.
Здесь, вероятно, нет идеального решения; это все просто компромиссы! Наше предпочтение - иметь неудачную CI задачу и вручную переопределить блокирующее правило защиты ветки, чтобы не было сюрпризов, и мы могли проактивно выполнить соответствующую команду в продакшене после слияния PR.
Расширение на тему "почему state:old
"
Для совершенно новых инкрементальных моделей вы хотите, чтобы они выполнялись в режиме full-refresh
в CI, потому что они будут выполняться в режиме full-refresh
в продакшене, когда PR будет слит в main
. Они также еще не существуют в производственной среде... они совершенно новые!
Если вы не укажете это, вы не получите ошибку, просто “No relation found in state manifest for…”. Таким образом, технически это работает без указания state:old
, но добавление state:old
более явно и означает, что он даже не попытается клонировать совершенно новые инкрементальные модели.