Learning Platform
Глоссарий Troubleshooting
Урок 18.03 · 18 мин
Начальный
dbtdata-modelingsnapshotssurrogate-keys

Роль dbt: staging, intermediate, marts

В прошлых уроках мы говорили о слоях (medallion) и о моделях (star schema, OBT), но обходили вопрос: чем всё это реально строят? Кто-то должен описать трансформации, которые превращают сырьё в витрины. В мире ELT стандартный ответ — dbt. Это не очередная методология моделирования, а инструмент, который превращает методологию в работающий код. Этот урок — про то, как dbt организует трансформации в слои, генерирует surrogate keys и реализует SCD2.

Коротко, что такое dbt. Это инструмент трансформаций для ELT: данные уже загружены в warehouse сырыми, dbt описывает SQL-трансформации, превращающие сырьё в модели. Каждая модель dbt — это файл с SQL-запросом SELECT; dbt сам строит из них граф зависимостей и выполняет в правильном порядке. Для нас важно одно: dbt задаёт дисциплину слоёв, и эта дисциплина — прямое продолжение всего, что вы уже изучили.


Три слоя dbt: staging, intermediate, marts

dbt-проект по соглашению организован в три слоя трансформаций. Названия отличаются от medallion (bronze/silver/gold), но идея слоёв зрелости — та же.

Три слоя моделей dbt
stagingОдин stg-файл на одну таблицу источника: переименование, типизация, лёгкая очистка. Кирпичики
комбинирование, бизнес-логика
intermediateПромежуточные модели: соединяют staging, считают бизнес-логику. Не для конечного потребителя
сборка финальных сущностей
martsФинальные витрины: dimensions и facts, с которыми работают аналитики и BI

Staging — нижний слой. Правило строгое: один staging-файл на одну таблицу источника. Staging-модель делает только лёгкие операции — переименование столбцов в единый стиль, приведение типов, простейшую очистку. Никаких JOIN, никакой бизнес-логики. Staging — это «причёсанные кирпичики»: каждая source-таблица в чистом, предсказуемом виде.

-- models/staging/stg_orders.sql
-- один файл на одну source-таблицу: переименование и типизация
SELECT
    id              AS order_id,
    cust_id         AS customer_id,
    CAST(dt AS DATE) AS order_date,
    CAST(amt AS DECIMAL(12,2)) AS amount
FROM {{ source('shop', 'orders') }}

Intermediate — средний слой. Здесь staging-модели соединяются, применяется бизнес-логика, считаются промежуточные результаты. Intermediate-модели — рабочие, их не отдают конечному потребителю напрямую; они существуют, чтобы разбить сложную трансформацию на читаемые шаги.

-- models/intermediate/int_orders_joined.sql
-- комбинируем staging-модели, добавляем бизнес-логику
SELECT
    o.order_id, o.order_date, o.amount,
    c.customer_segment,
    o.amount * 0.2 AS estimated_tax
FROM {{ ref('stg_orders') }} o
JOIN {{ ref('stg_customers') }} c ON o.customer_id = c.customer_id

Marts — верхний слой. Это финальные витрины: размерные модели — dim_customer, fct_orders — или OBT. Именно marts видят аналитики и BI. Marts собираются из intermediate и staging.

Обратите внимание на ref() в коде. Когда одна модель ссылается на другую через {{ ref('stg_orders') }}, dbt запоминает зависимость и строит граф (DAG). Из графа dbt сам выводит порядок: staging раньше intermediate, intermediate раньше marts. Вам не нужно вручную задавать очерёдность — она следует из ссылок.

Слой dbtАналог в medallionЧто делаетПрефикс
stagingоколо bronze/silverОдин файл на источник: переименование, типыstg_
intermediatesilverСоединение, бизнес-логика, промежуточные шагиint_
martsgoldФинальные dimensions и factsdim_ / fct_

Это та же идея слоёв зрелости, что и в medallion, но выраженная как структура файлов проекта. dbt не изобретает новую теорию — он даёт дисциплину, в которой теория из предыдущих модулей становится поддерживаемым кодом.


Surrogate keys в dbt

В модуле про ключи вы узнали про surrogate keys — искусственные идентификаторы. В размерной модели каждой dimension нужен surrogate key. dbt даёт для этого готовый инструмент — макрос generate_surrogate_key из пакета dbt_utils.

Макрос берёт один или несколько столбцов, конкатенирует их и считает хеш — получается detерминированный surrogate key. По сути это ровно тот же приём, что hash key в Data Vault: хеш от бизнес-ключа.

-- surrogate key dimension = хеш от business key
SELECT
    {{ dbt_utils.generate_surrogate_key(['customer_id']) }} AS customer_key,
    customer_id,
    customer_name,
    customer_city
FROM {{ ref('stg_customers') }}

-- для составного ключа — несколько столбцов:
-- {{ dbt_utils.generate_surrogate_key(['order_id', 'line_number']) }}

Почему хеш, а не автоинкремент? Те же причины, что в уроке про hash keys: хеш детерминирован (один business key всегда даёт один surrogate key — модель можно пересобрать, ключи не «поедут») и не требует централизованного счётчика (важно для параллельной обработки). Макрос обрабатывает разделители и NULL за вас. Это прямое применение того, что вы уже знаете о hash-based ключах, — просто упакованное в одну строку.

TIP

Заметьте сквозную линию курса: hash как surrogate key встречается в Data Vault (hash key), в Data Vault для change detection (hashdiff) и здесь, в dbt (generate_surrogate_key). Это один и тот же фундаментальный приём — детерминированный идентификатор из хеша бизнес-данных. Поняв его один раз, вы узнаёте его везде.

dbt-модели подробно — ref(), materializations, DAG в деталях

SCD2 в dbt: snapshots

В модуле про Slowly Changing Dimensions вы разобрали SCD Type 2: при изменении атрибута dimension добавляется новая строка с новым surrogate key, effective/end date и current flag, а старая версия сохраняется. Реализовать SCD2 руками — это аккуратный MERGE с закрытием старой версии и открытием новой; ошибиться легко.

dbt даёт для SCD2 встроенный механизм — snapshots. Вы описываете, за какой таблицей следить и как определять изменения, а dbt сам ведёт SCD2-логику.

-- snapshots/customers_snapshot.sql
{% snapshot customers_snapshot %}
{{ config(
    target_schema='snapshots',
    unique_key='customer_id',
    strategy='check',
    check_cols=['customer_name', 'customer_city', 'customer_segment']
) }}
SELECT * FROM {{ source('shop', 'customers') }}
{% endsnapshot %}

Что здесь происходит. unique_key — бизнес-ключ сущности. strategy='check' со списком check_cols означает: при каждом запуске dbt сравнивает значения этих столбцов с последней сохранённой версией — если хоть один изменился, фиксируется новая версия. Узнаёте? Это та же идея, что hashdiff в Data Vault: следим за набором атрибутов и реагируем на изменение. (Альтернативная стратегия — timestamp: dbt смотрит на столбец «последнего обновления».)

При запуске dbt snapshot инструмент сам ведёт служебные столбцы SCD2:

customer_id | customer_city | dbt_valid_from      | dbt_valid_to
1001        | Москва        | 2026-01-10 00:00:00 | 2026-03-20 00:00:00
1001        | Казань        | 2026-03-20 00:00:00 | (null)

dbt_valid_from и dbt_valid_to — это effective date и end date из урока про SCD2. У текущей версии dbt_valid_to равен NULL. Когда атрибут меняется, dbt закрывает старую строку (проставляет dbt_valid_to) и вставляет новую — ровно механика SCD2, только описанная декларативно. Вы говорите «веди SCD2 за этой таблицей», dbt делает MERGE правильно.

dbt snapshot ведёт SCD2 автоматически
Source-таблицаТекущее состояние сущности в источнике, без истории
dbt snapshot
Snapshot-таблицаИстория версий: dbt_valid_from, dbt_valid_to, строка на каждую версию
ref() в marts
dim_customerФинальная dimension с историей, построенная поверх snapshot

Важная деталь: snapshot нужно запускать регулярно. Источник хранит только текущее состояние; snapshot ловит изменения, лишь когда видит их при очередном запуске. Если между двумя запусками атрибут изменился дважды — промежуточное значение не попадёт в историю. Поэтому snapshot ставят на расписание, согласованное с тем, как часто меняются данные.


dbt как клей всего курса

Соберём картину. dbt не добавляет новой теории моделирования — он операционализирует теорию из предыдущих модулей:

  • Слои (medallion) -> staging / intermediate / marts как структура проекта.
  • Surrogate keys -> generate_surrogate_key, хеш от бизнес-ключа.
  • SCD Type 2 -> snapshots с dbt_valid_from / dbt_valid_to.
  • Граф зависимостей -> ref() строит DAG, dbt выводит порядок выполнения.

Поэтому dbt — стандартный инструмент аналитического инженера 2025-2026: он берёт концепции, которые вы изучили, и даёт способ выразить их как версионируемый, тестируемый, поддерживаемый код. В следующем уроке поднимемся ещё выше — к semantic layer, где определяются уже не таблицы, а сами бизнес-метрики.


Попробуй сам

  1. Возьмите две source-таблицы (orders, customers) и распишите для каждой staging-модель: какие столбцы переименуете, какие типы приведёте. Помните правило — один staging-файл на одну source-таблицу.
  2. Спроектируйте одну intermediate-модель, которая соединяет эти две staging-модели и добавляет вычисляемый столбец.
  3. Для dim_customer напишите строку с generate_surrogate_key. Объясните, почему хеш-ключ лучше автоинкремента при пересборке модели.
  4. Опишите snapshot для таблицы customers со стратегией check: какие check_cols вы укажете? Объясните, почему snapshot нужно запускать регулярно и что теряется при редком запуске.

Проверка знанийKnowledge check
Как dbt организует трансформации в слои и какими готовыми механизмами реализует surrogate keys и SCD Type 2?
ОтветAnswer
dbt организует трансформации в три слоя по зрелости — это та же идея, что medallion, но выраженная структурой файлов проекта. Staging (stg_): один файл на одну source-таблицу, только лёгкие операции — переименование столбцов, типизация, простая очистка, без JOIN и бизнес-логики. Intermediate (int_): staging-модели соединяются, применяется бизнес-логика, считаются промежуточные шаги; эти модели рабочие, не для конечного потребителя. Marts (dim_/fct_): финальные витрины — dimensions, facts или OBT, — с которыми работают аналитики. Ссылки между моделями через ref() строят граф зависимостей (DAG), из которого dbt сам выводит порядок выполнения. Surrogate keys dbt генерирует макросом generate_surrogate_key из dbt_utils: он конкатенирует столбцы бизнес-ключа и считает хеш — детерминированный ключ, как hash key в Data Vault; хеш лучше автоинкремента, потому что один business key всегда даёт один ключ и не нужен централизованный счётчик. SCD Type 2 dbt реализует через snapshots: вы декларативно описываете, за какой таблицей следить (unique_key) и как ловить изменения (стратегия check со списком check_cols либо timestamp), а dbt сам ведёт служебные столбцы dbt_valid_from и dbt_valid_to, закрывает старую версию и открывает новую — это механика SCD2, описанная декларативно. Snapshot нужно запускать регулярно: источник хранит только текущее состояние, и изменения между запусками не попадут в историю.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Какое правило действует для staging-слоя в dbt?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5