Defer
Defer — это мощная функция, которая позволяет запускать подмножество моделей или тестов в песочнице без необходимости сначала строить их родительские модели. Это может сэкономить время и вычислительные ресурсы, когда вы хотите протестировать небольшое количество моделей в большом проекте.
Defer требует, чтобы манифест из предыдущего вызова dbt был передан в флаг --state
или переменную окружения. Вместе с методом выбора state:
, эти функции позволяют реализовать "Slim CI". Подробнее о state.
Альтернативной командой, которая выполняет аналогичную функциональность для других случаев использования, является dbt clone
— см. документацию по clone для получения дополнительной информации.
Можно использовать отдельное состояние для state:modified
и --defer
, передавая пути к разным манифестам для каждого из --state
/DBT_STATE
и --defer-state
/DBT_DEFER_STATE
. Это позволяет более точно контролировать случаи, когда вы хотите сравнить с логическим состоянием из одной среды или прошлого момента времени и отложить применение состояния из другой среды или момента времени. Если --defer-state
не указан, откладывание будет использовать манифест, переданный в --state
. В большинстве случаев вы захотите использовать одно и то же состояние для обоих: сравнивать логические изменения с производством, а также "переключаться" на производственную среду для не построенных вышестоящих ресурсов.
Использование
dbt run --select [...] --defer --state path/to/artifacts
dbt test --select [...] --defer --state path/to/artifacts
По умолчанию dbt использует пространство име н target
для разрешения вызовов ref
.
Когда --defer
включен, dbt разрешает вызовы ref, используя манифест состояния, но только если:
- Узел не входит в число выбранных узлов, и
- Он не существует в базе данных (или используется
--favor-state
).
Эфемерные модели никогда не откладываются, так как они служат "переходами" для других вызовов ref
.
При использовании defer вы можете выбирать из производственных наборов данных, наборов данных для разработки или их комбинации. Обратите внимание, что это может привести к неожиданным результатам:
- если вы применяете ограничения, специфичные для среды, в разработке, но не в производстве, так как вы можете выбрать больше данных, чем ожидали
- при выполнении тестов, которые зависят от нескольких родителей (например,
relationships
), так как вы тестируете "между" средами
Откладывание требует установки как --defer
, так и --state
, либо путем явной передачи флагов, либо путем установки переменных окружения (DBT_DEFER
и DBT_STATE
). Если вы используете dbt Cloud, прочитайте о настройке CI задач.
Предпочтение состояния
Когда передан --favor-state
, dbt отдает приоритет определениям узлов из каталога --state
. Однако это не применяется, если узел также является частью выбранных узлов.
Пример
В моей локальной среде разработки я создаю все модели в моей целевой схеме, dev_alice
. В производстве те же модели создаются в схеме с именем prod
.
Я получаю доступ к dbt-сгенерированным артефактам (а именно manifest.json
) из производственного запуска и копирую их в локальный каталог под названием prod-run-artifacts
.
run
Я работал над model_b
:
select
id,
count(*)
from {{ ref('model_a') }}
group by 1
Я хочу протестировать свои изменения. В моей схеме разработки, dev_alice
, ничего не существует.
- Стандартный запуск
- Отложенный запуск
dbt run --select "model_b"
create or replace view dev_me.model_b as (
select
id,
count(*)
from dev_alice.model_a
group by 1
)
Если я ранее не запускал model_a
в этой среде разработки, dev_alice.model_a
не будет существовать, что вызовет ошибку базы данных.
dbt run --select "model_b" --defer --state prod-run-artifacts
create or replace view dev_me.model_b as (
select
id,
count(*)
from prod.model_a
group by 1
)
Поскольку model_a
не выбран, dbt проверит, существует ли dev_alice.model_a
. Если он не существует, dbt разрешит все экземпляры {{ ref('model_a') }}
в prod.model_a
.
test
У меня также есть тест relationships
, который устанавливает ссылочную целостность между model_a
и model_b
:
version: 2
models:
- name: model_b
columns:
- name: id
tests:
- relationships:
to: ref('model_a')
field: id
(Немного глупо, так как все данные в model_b
должны были поступить из model_a
, но давайте предположим это.)
- Без defer
- С defer
dbt test --select "model_b"
select count(*) as validation_errors
from (
select id as id from dev_alice.model_b
) as child
left join (
select id as id from dev_alice.model_a
) as parent on parent.id = child.id
where child.id is not null
and parent.id is null
Тест relationships
требует как model_a
, так и model_b
. Поскольку я не построил model_a
в своем предыдущем dbt run
, dev_alice.model_a
не существует, и этот тестовый запрос не выполняется.
dbt test --select "model_b" --defer --state prod-run-artifacts
select count(*) as validation_errors
from (
select id as id from dev_alice.model_b
) as child
left join (
select id as id from prod.model_a
) as parent on parent.id = child.id
where child.id is not null
and parent.id is null
dbt проверит, существует ли dev_alice.model_a
. Если он не существует, dbt разрешит все экземпляры {{ ref('model_a') }}
, включая те, что в тестах схемы, использовать prod.model_a
. Запрос выполняется успешно. Вопрос, действительно ли я хочу тестировать ссылочную целостность между средами, остается открытым.