# Defer

Defer — это мощная функция, которая позволяет запускать подмножество (Версии dbt: v1.11 и новее) моделей, тестов или функций в [изолированной среде](https://docs.getdbt.tech/docs/environments-in-dbt.md) без предварительного построения их вышестоящих родительских моделей. Это позволяет сэкономить время и вычислительные ресурсы, когда нужно протестировать небольшое количество моделей в большом проекте.

[![Используйте 'defer', чтобы модифицировать модели в конце конвейера, указывая на производственные модели, вместо того чтобы запускать все вышестоящие.](/img/docs/reference/defer-diagram.png?v=2 "Используйте 'defer', чтобы модифицировать модели в конце конвейера, указывая на производственные модели, вместо того чтобы запускать все вышестоящие.")](#)Используйте 'defer', чтобы модифицировать модели в конце конвейера, указывая на производственные модели, вместо того чтобы запускать все вышестоящие.

Для использования defer требуется манифест из предыдущего вызова dbt. Укажите путь с помощью флага `--state` или переменной окружения (Версии dbt: v1.11 и новее) `DBT_ENGINE_STATE`. Вместе с методом выбора `state:` эти возможности позволяют реализовать «Slim CI». Подробнее читайте в разделе [Состояние](https://docs.getdbt.tech/reference/node-selection/state-selection.md).

В некоторых случаях для достижения аналогичного результата можно использовать `dbt clone`. Подробнее см. в разделе [clone](https://docs.getdbt.tech/reference/commands/clone.md#when-to-use-dbt-clone-instead-of-deferral).

Для `state:modified` и `--defer` можно использовать разные состояния, передав пути к разным манифестам через `--state`/(Версии dbt: v1.11 и новее) `DBT_ENGINE_STATE` и `--defer-state`/(Версии dbt: v1.11 и новее) `DBT_ENGINE_DEFER_STATE` соответственно. Это обеспечивает более точный контроль в случаях, когда вы хотите:

* Сравнивать с логическим состоянием из одной среды или на определённый момент в прошлом
* Использовать для defer применённое состояние из другой среды или на другой момент времени

Если `--defer-state` не указан, для defer будет использоваться манифест, переданный через `--state`. В большинстве случаев для обеих задач стоит использовать одно и то же состояние: сравнивать логические изменения с производственной средой, а для невыполненных вышестоящих ресурсов также «переключаться» на производственную среду.

### Использование

```shell
dbt run --select [...] --defer --state path/to/artifacts
dbt test --select [...] --defer --state path/to/artifacts
```

По умолчанию dbt использует пространство имён [`target`](https://docs.getdbt.tech/reference/dbt-jinja-functions/target.md) для разрешения вызовов `ref`.

Когда включён `--defer`, dbt разрешает вызовы `ref`(Версии dbt: v1.11 и новее) и `function`, используя манифест состояния, но только если:

1. Узел не входит в число выбранных узлов, *и*
2. Он не существует в базе данных (или используется `--favor-state`).

Эфемерные модели никогда не используют отложенное разрешение ссылок, поскольку они служат «промежуточными звеньями» для других вызовов `ref`.

(Версии dbt: v1.11 и новее)

Для [пользовательских функций (UDF)](https://docs.getdbt.tech/docs/build/udfs.md), на которые ссылаются с помощью `{{ function('...') }}`, отложенное разрешение ссылок применяется при тех же условиях. В этом случае `function()` разрешается в определение функции из манифеста состояния, если UDF не выбрана или не создана в текущем целевом окружении.

к сведению

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

* Если в окружении разработки вы применяете ограничения, зависящие от окружения, а в рабочем окружении — нет, вы можете выбрать больше данных, чем ожидалось.
* Тесты, зависящие от нескольких родительских объектов (например, `relationships`), могут выполняться с использованием данных из разных окружений.

Для отложенного разрешения ссылок необходимо задать и `--defer`, и `--state`: либо явно передав флаги, либо установив переменные окружения ((Версии dbt: v1.11 и новее) `DBT_ENGINE_DEFER` и `DBT_ENGINE_STATE`). Подробнее см. в разделе [Непрерывная интеграция](https://docs.getdbt.tech/docs/deploy/continuous-integration.md).

#### Предпочтение состояния

Когда передан `--favor-state`, dbt отдает приоритет определениям узлов из каталога `--state`. Однако это не применяется, если узел также является частью выбранных узлов.

При передаче `--favor-state` dbt отдает приоритет определениям узлов из каталога `--state`. Однако это не применяется, если узел также входит в число выбранных узлов.

В моей локальной среде разработки я создаю все модели в моей целевой схеме, `dev_alice`. В производстве те же модели создаются в схеме с именем `prod`.

Я получаю доступ к dbt-сгенерированным [артефактам](https://docs.getdbt.tech/docs/deploy/artifacts.md) (а именно `manifest.json`) из производственного запуска и копирую их в локальный каталог под названием `prod-run-artifacts`.

### run

Я работал над `model_b`:

models/model\_b.sql

```sql
select

    id,
    count(*)

from {{ ref('model_a') }}
group by 1
```

Я хочу протестировать свои изменения. В моей схеме разработки, `dev_alice`, ничего не существует.

### Стандартный запуск

```shell
dbt run --select "model_b"
```

target/run/my\_project/model\_b.sql

```sql
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` не будет существовать, что вызовет ошибку базы данных.

### Отложенный запуск

```shell
dbt run --select "model_b" --defer --state prod-run-artifacts
```

target/run/my\_project/model\_b.sql

```sql
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`:

models/resources.yml

```yml

models:
  - name: model_b
    columns:
      - name: id
        data_tests:
          - relationships:
              arguments: # available in v1.10.5 and higher. Older versions can set the <argument_name> as the top-level property.
                to: ref('model_a')
                field: id
```

(Это упрощённый пример, поскольку все данные в `model_b` уже поступают из `model_a`)

### Без defer

```shell
dbt test --select "model_b"
```

target/compiled/.../relationships\_model\_b\_id\_\_id\_\_ref\_model\_a\_.sql

```sql
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` не существует, и этот тестовый запрос не выполняется.

### С defer

```shell
dbt test --select "model_b" --defer --state prod-run-artifacts
```

target/compiled/.../relationships\_model\_b\_id\_\_id\_\_ref\_model\_a\_.sql

```sql
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`. Запрос выполняется успешно. Вопрос, действительно ли я хочу тестировать ссылочную целостность между средами, остается открытым.

## Связанная документация

* [Использование defer в dbt](https://docs.getdbt.tech/docs/platform/about-defer.md)

* [on\_configuration\_change](https://docs.getdbt.tech/reference/resource-configs/on_configuration_change.md)

* [Использование defer в dbt Cloud](https://docs.getdbt.tech/docs/platform/about-defer.md)

* [on\_configuration\_change](https://docs.getdbt.tech/reference/resource-configs/on_configuration_change.md)
