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
  • Documentationdescription, генерация 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-arriving
  • merge — 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_at
  • check — сравнение по списку колонок

Подробнее — 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_id

Singular 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 — собирает meta
  • dbt 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-модели.

Смотрите также