dbt и моделирование на собеседовании Data Engineer
Зачем dbt на собесе DE
dbt (data build tool) — стандарт современного ELT-стека: декларативные SQL-модели, тесты, документация, версионирование. На собесе Data Engineer dbt спрашивают, если команда работает на современном lakehouse-стеке (Snowflake / BigQuery / ClickHouse / Greenplum + dbt + Airflow).
dbt вытесняет ручные ETL-скрипты: вместо «Python код пишет в табличку» — декларативная модель в SQL, которая знает, что от чего зависит. На большинство DE-вакансий в 2026 dbt — обязательный навык.
Что такое dbt
dbt — это transformation layer над DWH. ELT, не ETL: данные сначала грузятся в DWH (E + L), потом dbt трансформирует их в production-таблицы (T).
Ключевые концепты:
- Models — SQL-файлы, каждый = одна таблица или view
- Sources — внешние таблицы (от ELT-loader: Fivetran / Airbyte)
- Refs — зависимости между моделями (
{{ ref('stg_orders') }}) - Tests — встроенные проверки (
unique,not_null,accepted_values,relationships) - Snapshots — для slowly changing dimensions
- Macros — reusable SQL через Jinja templating
- Documentation —
description, генерация data catalog
Подробнее — dbt tests deep на собесе DE.
Layered modeling
Стандартный подход (по официальной dbt-best-practices):
1. Staging (stg_): 1-к-1 с source, очистка имён, type casting, light cleanup.
2. Intermediate (int_): промежуточные joins, complex logic, переиспользуется в нескольких mart-моделях.
3. Marts (fct_ / dim_): финальные таблицы для BI и аналитиков. Star schema, dimensional modeling.
Пример:
raw.orders (Fivetran) →
stg_orders.sql (cleanup, type casting) →
int_orders_with_customers.sql (join с customers) →
fct_orders.sql (final mart для BI)Incremental models
Для больших таблиц, которые не пересчитываются с нуля каждую ночь.
{{ config(materialized='incremental', unique_key='order_id') }}
SELECT * FROM {{ ref('stg_orders') }}
{% if is_incremental() %}
WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }})
{% endif %}Strategies:
append— простой insert. Risk дубликатов, если данные late-arrivingmerge— upsert поunique_key. Стандарт для модерн DWH (Snowflake, BigQuery)delete+insert— удалить partition, insert новые. Для partition-based incremental
Snapshots (SCD Type 2)
Для медленно меняющихся измерений: история изменений атрибутов.
{% snapshot customers_snapshot %}
{{ config(target_schema='snapshots', unique_key='customer_id', strategy='TIMESTAMP', updated_at='updated_at') }}
SELECT * FROM {{ source('raw', 'customers') }}
{% endsnapshot %}dbt создаёт колонки dbt_valid_from, dbt_valid_to, dbt_scd_id — стандарт SCD Type 2.
Strategies:
timestamp— сравнение поupdated_atcheck— сравнение по списку колонок
Подробнее — data modeling subtopic.
Тесты в dbt
Generic tests (встроенные):
columns:
- name: order_id
tests:
- unique
- not_null
- name: status
tests:
- accepted_values:
values: ['open', 'paid', 'cancelled']
- name: customer_id
tests:
- relationships:
to: ref('dim_customers')
field: customer_idSingular tests: произвольный SQL, возвращающий «плохие строки». Если пустой результат — тест прошёл.
Packages: dbt-utils, dbt-expectations — расширенные тесты.
CI/CD для dbt
Pre-merge checks:
dbt parse— синтаксисdbt build --select state:modified+— собираем только изменённые моделиdbt test— все тесты
Production:
- Airflow / Dagster запускают
dbt runпо расписанию - Slim CI:
dbt run --select state:modified+для PR - Deferred state: использовать prod manifest как baseline
Документация
dbt автоматически генерирует data catalog:
dbt docs generate— собирает metadbt docs serve— поднимает локально
В каждой модели в YAML:
- name: fct_orders
description: "Final orders fact table for analytics"
columns:
- name: order_id
description: "Primary key, unique order identifier"Типичные вопросы
«Зачем dbt vs Python ETL?»
Декларативность (SQL вместо процедурного кода), автоматический DAG зависимостей, встроенные тесты, документация. Для analytical workloads — стандарт. Python ETL остаётся для ML pipelines.
«Incremental или full refresh?»
Full refresh: small tables (<10M строк), сложная логика с window functions через всю историю. Incremental: large tables, late-arriving data легко handle через merge.
«Snapshot vs delete-load?»
Snapshot (SCD Type 2) — нужна история изменений атрибутов (например, как менялся pricing tier customer-а). Delete-load — нужна только current state.
«dbt vs Dataform vs SQLMesh?»
dbt — самый зрелый, большое community. Dataform — Google, integrated с BigQuery. SQLMesh — современная альтернатива с virtual environments и data diffing.
Частые ошибки
- Layered modeling игнорируется. Без staging / intermediate — мерж всего в одной модели, нерасширяемо
- Без тестов. dbt без тестов — просто SQL-runner. Тесты обязательны
- Full refresh для большой таблицы. Тайм-аут или сжигание бюджета DWH
- Игнор documentation. В команде из 3 человек без docs работает. В команде из 30 — ад
- Modeling в Python instead of dbt. Современный стек требует SQL-first подход
FAQ
dbt Core или dbt Cloud?
Core — open-source, бесплатный. Cloud — managed UI, scheduler, alerts. На собес знать оба, на проде часто Core + Airflow.
Нужно ли учить Jinja?
Базовая Jinja — да: {{ ref() }}, {% if %}, циклы для macros. Глубже — по мере необходимости.
dbt и ClickHouse?
dbt-clickhouse — стабильный adapter. dbt + ClickHouse — популярная связка в Яндексе, X5, и других.
Можно ли dbt для real-time?
Нет, dbt — batch transformation. Для real-time — Materialize, RisingWave, Flink.
Кто пишет dbt: DE или аналитики?
В небольших командах часто аналитики (analytics engineer). В крупных — DE проектирует архитектуру, аналитики пишут mart-модели.