contract
Поддерживается в dbt версии 1.5 и выше.
Когда конфигурация contract применяется, dbt будет гарантировать, что возвращаемый набор данных вашей модели точно соответствует атрибутам, которые вы определили в yaml:
nameиdata_typeдля каждого столбца- Дополнительные
ограничения, как поддерживается для этой материализации и платформы данных
Это необходимо для того, чтобы люди, выполняющие запросы к вашей модели далее по цепочке — как внутри, так и вне dbt — имели предсказуемый и согласованный набор столбцов для использования в своих анализах. Даже незначительное изменение типа данных, например, из boolean (true/false) в integer (0/1), может привести к неожиданным сбоям запросов.
Поддержка
В настоящее время контракты моделей поддерживаются для:
- SQL моделей (пока не для Python)
- Моделей, материализованных как
table,viewиincremental(сon_schema_change: append_new_columnsилиon_schema_change: fail) - Наиболее популярных платформ данных — хотя поддержка и применение различных типов ограничений варьируются в зависимости от платформы
Алиасинг типов данных
dbt использует встроенный алиасинг типов для data_type, определенного в вашем YAML. Например, вы можете указать string в вашем контракте, и на Postgres/Redshift dbt преобразует его в text. Если dbt не распознает имя data_type среди известных алиасов, он передаст его как есть. Это включено по умолчанию, но вы можете отказаться, установив alias_types в false.
Пример отключения:
models:
- name: my_model
config:
contract:
enforced: true
alias_types: false # true по умолчанию
Размер, точность и масштаб
Когда dbt сравнивает типы данных, он не будет сравнивать такие детальные характеристики, как размер, точность или масштаб. Мы считаем, что вам не стоит беспокоиться о разнице между varchar(256) и varchar(257), так как это не сильно влияет на опыт пользователей, выполняющих запросы далее по цепочке. Вы можете добиться более точного утверждения, написав или используя пользовательский тест.
Обратите внимание, что вам нужно указать размер varchar или масштаб числового типа, иначе dbt полагается на значения по умолчанию. Например, если тип numeric по умолчанию имеет точность 38 и масштаб 0, то числовой столбец хранит 0 цифр справа от десятичной точки (он хранит только целые числа), что может привести к сбою применения контракта. Чтобы избежать этого неявного приведения, укажите ваш data_type с ненулевым масштабом, например, numeric(38, 6). dbt Core 1.7 и выше выдает предупреждение, если вы не указываете точность и масштаб при предоставлении числового типа данных.
Пример
models:
- name: dim_customers
config:
materialized: table
contract:
enforced: true
columns:
- name: customer_id
data_type: int
constraints:
- type: not_null
- name: customer_name
data_type: string
- name: non_integer
data_type: numeric(38,3)
Предположим, ваша модель определена как:
select
'abc123' as customer_id,
'My Best Customer' as customer_name
Когда вы выполняете dbt run для вашей модели, до того, как dbt материализует ее как таблицу в базе данных, вы увидите эту ошибку:
20:53:45 Ошибка компиляции в модели dim_customers (models/dim_customers.sql)
20:53:45 Эта модель имеет применяемый контракт, который не выполнен.
20:53:45 Пожалуйста, убедитесь, что имя, data_type и количество столбцов в вашем контракте соответствуют столбцам в определении вашей модели.
20:53:45
20:53:45 | column_name | definition_type | contract_type | mismatch_reason |
20:53:45 | ----------- | --------------- | ------------- | ------------------ |
20:53:45 | customer_id | TEXT | INT | несоответствие типа данных |
20:53:45
20:53:45
20:53:45 > в макросе assert_columns_equivalent (macros/materializations/models/table/columns_spec_ddl.sql)
Инкрементальные модели и on_schema_change
Почему требуется, чтобы инкрементальные модели также устанавливали on_schema_change, и почему append_new_columns?
Почему для инкрементальных моделей требуется также указывать on_schema_change, и почему именно append_new_columns или fail?
Инкрементальные модели по своей природе предполагают, что структура таблицы в хранилище данных уже существует и используется повторно от запуска к запуску. Если схема (набор столбцов) модели меняется, это может привести к неоднозначному или некорректному поведению при инкрементальной загрузке данных.
Требование явно указывать параметр on_schema_change заставляет автора модели осознанно выбрать, как dbt должен реагировать на такие изменения схемы, вместо того чтобы полагаться на неявное или «магическое» поведение. Это снижает риск незаметных ошибок и потери данных.
Допустимые значения ограничены append_new_columns и fail, потому что именно эти варианты считаются безопасными и предсказуемыми в контексте инкрементальных моделей:
append_new_columns— dbt автоматически добавит новые столбцы в целевую таблицу, не затрагивая существующие данные. Это наиболее распространённый и относительно безопасный сценарий эволюции схемы.fail— dbt остановит выполнение с ошибкой, если схема изменилась. Это подходит для случаев, когда любые изменения схемы должны быть явно рассмотрены и обработаны вручную.
Другие варианты изменения схемы (например, удаление или переименование столбцов) могут привести к потере данных или нарушению логики инкрементальной загрузки, поэтому dbt не позволяет использовать их автоматически для инкрементальных моделей.
Почему append_new_columns, а не sync_all_columns? Потому что удаление существующих столбцов является критическим изменением для моделей с контрактами!
Почему используется append_new_columns (или fail), а не sync_all_columns? Потому что удаление существующих колонок является ломающим изменением (breaking change) для моделей с контрактом! sync_all_columns работает так же, как append_new_columns, но дополнительно удаляет удалённые колонки, а этого нельзя делать для моделей с контрактом, если только вы не повышаете версию.