Урок по треку Data Engineering 7 мин

dbt: трансформации как код

Модели и ref, source, материализации, инкрементальные модели, тесты, снапшоты, слои staging, intermediate, marts.

dbt (data build tool) превращает SQL-трансформации в хранилище в проект с зависимостями, тестами, документацией и CI. Это буква T в ELT: данные уже загружены, dbt строит из них модели. В вакансиях дата-инженеров и аналитиков-инженеров в 2026 году dbt встречается постоянно.

Модель

Модель это файл .sql с одним SELECT. dbt сам оборачивает его в CREATE TABLE AS или CREATE VIEW AS.

-- models/marts/fct_orders.sql
select
    o.order_id,
    o.customer_id,
    o.created_at::date as order_date,
    sum(i.amount) as amount
from {{ ref('stg_orders') }} o
join {{ ref('stg_order_items') }} i using (order_id)
group by 1, 2, 3
  • {{ ref('модель') }} ссылается на другую модель. dbt по ссылкам строит граф зависимостей (DAG), запускает модели в правильном порядке и подставляет правильную схему окружения (dev, prod).
  • {{ source('схема', 'таблица') }} ссылается на сырые таблицы, загруженные извне. Для источников можно описать проверку свежести.
  • Jinja позволяет писать макросы, циклы и условия, но злоупотреблять ими не стоит: SQL должен оставаться читаемым.

Материализации

  • view: представление, всегда свежее, но считается при каждом запросе.
  • table: таблица пересоздаётся целиком при каждом запуске.
  • incremental: при первом запуске таблица создаётся, дальше обрабатываются только новые или изменённые строки.
  • ephemeral: модель не создаётся в базе, а встраивается как CTE в зависящие модели.
  • Ещё бывают материализованные представления, если хранилище их поддерживает.

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

{{ config(materialized='incremental', unique_key='order_id') }}

select order_id, status, amount, updated_at
from {{ ref('stg_orders') }}
{% if is_incremental() %}
where updated_at > (select max(updated_at) from {{ this }})
{% endif %}
  • is_incremental() истинно, когда таблица уже существует и запуск не полный.
  • {{ this }} ссылается на текущую модель в базе.
  • unique_key определяет, как вставлять: при совпадении ключа строка обновляется (merge или delete+insert в зависимости от адаптера и стратегии), иначе дописывается.
  • Опоздавшие данные: фильтр > max(updated_at) пропустит строки, пришедшие с опозданием и меткой времени раньше максимума. Часто берут окно с запасом: >= max(updated_at) - interval '3 days', а дубли гасит unique_key.
  • dbt run --full-refresh пересобирает модель целиком, например после изменения логики.

Тесты

Data tests (так их называют с dbt 1.8) проверяют данные в базе. Встроенные generic-тесты в YAML:

models:
  - name: fct_orders
    columns:
      - name: order_id
        data_tests: [unique, not_null]
      - name: customer_id
        data_tests:
          - relationships:
              to: ref('dim_customers')
              field: customer_id
      - name: status
        data_tests:
          - accepted_values:
              values: ['new', 'paid', 'cancelled']

Тест это запрос, который ищет плохие строки: если он вернул строки, тест упал. Можно писать свои singular-тесты обычным SQL и подключать пакеты (например, dbt-utils, dbt-expectations). С dbt 1.8 появились также unit tests: проверка логики модели на заданных входных строках без реальных данных.

dbt build запускает модели, тесты, снапшоты и сиды в порядке графа: если тест модели упал, зависимые модели не строятся.

Снапшоты

Snapshot реализует SCD 2 для изменяемой таблицы источника: dbt хранит версии строк с колонками dbt_valid_from и dbt_valid_to. Стратегии:

  • timestamp: изменение определяется по колонке времени обновления.
  • check: сравниваются значения перечисленных колонок.

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

Слои проекта

Типичная структура:

  • staging: одна модель на таблицу источника, переименование, приведение типов, без джойнов. Обычно view.
  • intermediate: промежуточная логика, джойны и подготовка.
  • marts: факты и измерения для потребителей, таблицы или инкрементальные модели.

Плюс сиды (seeds, небольшие CSV-справочники в репозитории), макросы, документация (dbt docs с графом lineage), окружения через profiles и target.

dbt в процессе

  • Проект в git, изменения через merge request.
  • CI собирает изменённые модели и их потомков (state:modified+) во временной схеме и прогоняет тесты.
  • Продакшн-запуск по расписанию из оркестратора (Airflow, Dagster) или dbt Cloud.

Частые ошибки

  • Хардкод имён таблиц вместо ref и source: ломается граф и окружения.
  • Инкрементальная модель без unique_key и без учёта опозданий.
  • Вся логика в одной модели на 500 строк вместо слоёв.
  • Тесты только на unique и not_null у ключа и больше ничего.
  • Jinja ради Jinja: макросы, которые никто не может прочитать.

Что спросят на собесе

  • Что такое модель, ref и source, как dbt строит граф.
  • Материализации и когда какую выбирать.
  • Как работает инкрементальная модель и что делать с опозданиями.
  • Какие тесты бывают, что делает dbt build.
  • Снапшоты и их связь с SCD 2.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.