dbt у 2026 році: трансформація даних, тестування та питання для співбесід
Повний гайд з dbt для дата-інженерів: пошарова модель даних, матеріалізації, стратегії тестування якості та реальні питання для технічних співбесід 2026 року.

dbt (data build tool) став стандартним фреймворком для трансформації даних у сучасних аналітичних сховищах. Станом на 2026 рік понад 40 000 компаній використовують dbt у продакшн-середовищах для побудови надійних data-пайплайнів. Цей гайд охоплює ключові механіки dbt-трансформацій, стратегії тестування якості даних та питання, які найчастіше зустрічаються на технічних співбесідах з data engineering.
dbt відповідає за T (Transform) у підході ELT. Він компілює SQL SELECT-запити у DDL-інструкції (CREATE TABLE, CREATE VIEW, MERGE) та виконує їх безпосередньо у сховищі даних — Snowflake, BigQuery, Redshift або Databricks. Контроль версій, розв'язання залежностей, тестування та документація входять до базової функціональності.
Пошарова модель: Staging, Intermediate та Marts
Добре структурований dbt-проєкт розділяє трансформації на три рівні. Такий підхід, популяризований dbt-спільнотою, забезпечує принцип єдиної відповідальності для кожної моделі та значно спрощує діагностику проблем.
Staging-моделі розташовані найближче до сирих даних. Їхня функція чітко обмежена: перейменування колонок, приведення типів та фільтрація некоректних записів. Жодних JOIN-операцій та агрегацій на цьому рівні.
-- models/staging/stg_orders.sql
WITH source AS (
SELECT * FROM {{ source('ecommerce', 'raw_orders') }}
)
SELECT
id AS order_id,
customer_id,
CAST(order_date AS DATE) AS order_date,
CAST(amount AS DECIMAL(10, 2)) AS order_amount,
LOWER(status) AS order_status
FROM source
WHERE id IS NOT NULLIntermediate-моделі застосовують бізнес-логіку — JOIN-операції, агрегації, віконні функції. Вони посилаються на staging-моделі через функцію ref(), яка реєструє залежності у DAG.
-- models/intermediate/int_customer_orders.sql
WITH orders AS (
SELECT * FROM {{ ref('stg_orders') }}
),
customers AS (
SELECT * FROM {{ ref('stg_customers') }}
)
SELECT
c.customer_id,
c.customer_name,
COUNT(o.order_id) AS total_orders,
SUM(o.order_amount) AS lifetime_value,
MIN(o.order_date) AS first_order_date,
MAX(o.order_date) AS last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_nameMarts — це фінальний рівень споживання: чисті, задокументовані таблиці, до яких безпосередньо звертаються дашборди та аналітики.
Пошарова архітектура гарантує, що збій у джерелі даних вплине лише на staging-рівень, а не на весь пайплайн. Кожен рівень може тестуватися незалежно від інших.
Функція ref() та побудова DAG
ref() — це не просто аліас для імені таблиці. Виклик {{ ref('stg_orders') }} виконує дві операції одночасно: розв'язує повне кваліфіковане ім'я таблиці на етапі компіляції та реєструє ребро залежності у направленому ациклічному графі (DAG) dbt. Без ref() dbt не має можливості визначити порядок виконання моделей.
Поширена помилка — хардкодинг імен таблиць замість використання ref(). Це порушує відстеження залежностей і може призвести до виконання моделей раніше, ніж їхні upstream-залежності будуть готові.
-- Bad: hardcoded reference, no dependency tracking
SELECT * FROM analytics.stg_orders
-- Good: ref() registers the dependency
SELECT * FROM {{ ref('stg_orders') }}DAG також забезпечує роботу таких команд, як dbt run --select stg_orders+, яка запускає модель та все, що від неї залежить нижче по графу. Це корисно для цільових перебудов після зміни схеми джерела даних.
Матеріалізації: вибір стратегії зберігання
dbt пропонує чотири вбудовані матеріалізації, кожна з яких підходить для різних патернів доступу до даних та обсягів.
| Materialization | Storage | Best for | Trade-off |
|----------------|---------|----------|----------|
| view | No storage (computed on read) | Lightweight transforms, small datasets | Slow reads on large data |
| table | Full table rebuild each run | Mart-layer models, fast reads | Rebuilds everything, higher cost |
| incremental | Appends/merges new rows only | Large fact tables, event streams | More complex logic, needs unique_key |
| ephemeral | Inlined as CTE, never materialized | Reusable logic shared across models | Cannot be queried directly |
За замовчуванням використовується view. Перевизначити матеріалізацію можна у конфігураційному блоці моделі або у dbt_project.yml:
-- models/marts/fct_daily_revenue.sql
{{
config(
materialized='incremental',
unique_key='revenue_date',
incremental_strategy='merge'
)
}}
SELECT
DATE(order_date) AS revenue_date,
SUM(order_amount) AS daily_revenue,
COUNT(DISTINCT customer_id) AS unique_customers
FROM {{ ref('stg_orders') }}
WHERE order_status = 'completed'
{% if is_incremental() %}
AND order_date > (SELECT MAX(revenue_date) FROM {{ this }})
{% endif %}
GROUP BY DATE(order_date)Блок is_incremental() виконується лише під час інкрементальних запусків. При повному оновленні (dbt run --full-refresh) він пропускається, і таблиця перебудовується з нуля.
Готовий до співбесід з Data Engineering?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Тестування якості даних на кожному рівні
dbt надає дві категорії тестів: generic-тести, оголошені у YAML-файлах, та singular-тести — окремі SQL-файли, які повертають рядки у випадку порушення.
Generic-тести покривають структурні обмеження:
# models/staging/_stg_models.yml
version: 2
models:
- name: stg_orders
columns:
- name: order_id
tests:
- unique
- not_null
- name: order_status
tests:
- accepted_values:
values: ['completed', 'pending', 'cancelled', 'refunded']
- name: customer_id
tests:
- not_null
- relationships:
to: ref('stg_customers')
field: customer_idSingular-тести перевіряють бізнес-правила, які неможливо виразити за допомогою generic-тестів:
-- tests/assert_revenue_never_negative.sql
SELECT
revenue_date,
daily_revenue
FROM {{ ref('fct_daily_revenue') }}
WHERE daily_revenue < 0Unit-тести, запроваджені у dbt 1.8, дозволяють перевіряти логіку трансформацій з контрольованими вхідними даними та очікуваними результатами — без необхідності звертатися до сховища. Вони виконуються безпосередньо у фазі dbt test.
Стратегія тестування повинна відповідати потоку даних: перевірки свіжості джерел та підрахунок рядків, schema-тести на staging-рівні (not_null, unique), перевірка референційної цілісності на intermediate-рівні та бізнес-асерції на рівні marts.
dbt Core v1.10 та Fusion Engine
dbt Core v1.10 запровадив прапорець --sample для команд run та build. Цей прапорець застосовує вибірку на основі часу до ref() та source(), дозволяючи розробникам валідувати трансформації на підмножині даних без витрат на повну побудову. Особливо корисно для ітерацій над моделями, що базуються на фактових таблицях з мільярдами рядків.
Fusion Engine — повна переписка ядра dbt на Rust — тепер є стандартом для нових проєктів у dbt Cloud на Snowflake, BigQuery, Redshift та Databricks. Fusion запроваджує семантичне версіонування, починаючи з 2.0, та забезпечує суттєве покращення продуктивності компіляції та виконання.
Серед інших помітних нововведень 2026 року: YAML-специфікація Semantic Layer для централізованого визначення метрик, Cost Insights (бета) для оцінки обчислювальних витрат сховища на модель, а також нативні приватні пакети, що тепер загальнодоступні.
Макроси та Jinja для повторного використання логіки
Коли один і той самий SQL-патерн зустрічається у кількох моделях, його варто винести у макрос. Макроси — це Jinja-функції, що зберігаються у директорії macros/.
-- macros/cents_to_dollars.sql
{% macro cents_to_dollars(column_name) %}
ROUND(CAST({{ column_name }} AS DECIMAL(10, 4)) / 100, 2)
{% endmacro %}Виклик у будь-якій моделі:
-- models/staging/stg_payments.sql
SELECT
payment_id,
order_id,
{{ cents_to_dollars('amount_cents') }} AS amount_dollars,
payment_method
FROM {{ source('stripe', 'payments') }}Такий підхід забезпечує дотримання принципу DRY. Альтернатива — копіювання формули конвертації у кожну модель, де вона потрібна — створює додаткові витрати на підтримку та ризик неузгодженості.
Питання, які реально задають на співбесідах
Співбесіди з data engineering у 2026 році все частіше перевіряють знання dbt за межами базових понять. Нижче наведено питання, які дозволяють відрізнити досвідчених кандидатів, зібрані на основі патернів, що зустрічаються на позиціях у компаніях із сучасним стеком даних.
П: Інкрементальна модель перебудувала всю таблицю вночі. Що сталося?
Найпоширеніша причина: колонка unique_key містила NULL-значення. Коли dbt намагається виконати MERGE за ключем із NULL, зіставлення не спрацьовує для жодного рядка, тому відбувається вставка дублікатів. Друга причина: хтось запустив dbt run --full-refresh, не усвідомлюючи, що це перебудовує таблицю з нуля. Третя: фільтр is_incremental() посилався на колонку, якої ще не існує у цільовій таблиці (перший запуск проти наступних). Діагностика починається з перевірки скомпільованого SQL у target/compiled/.
П: Як правильно розподілити тести у продакшн dbt-проєкті?
Перш за все виконуються перевірки свіжості джерел — якщо джерело не оновлювалося, downstream-моделі не повинні працювати на застарілих даних. Staging-тести валідують обмеження схеми: первинні ключі (unique + not_null), допустимі значення та приведення типів. Intermediate-тести перевіряють референційну цілісність між JOIN-операціями. Mart-тести перевіряють бізнес-інваріанти: виручка >= 0, активних користувачів >= платних користувачів, сума частин дорівнює загальному підсумку. Усі тести виконуються у CI на pull request-ах у dev-схемі, а потім повторно після деплою у продакшн з налаштованими алертами.
П: Коли модель має бути ephemeral, а коли view?
Ephemeral-моделі вбудовують свій SQL як CTE у моделі, що їх споживають — корисно для повторюваної логіки, яку не потрібно запитувати окремо. View обчислюються при читанні та існують як об'єкти, до яких можна звертатися. Компроміс: ephemeral-моделі не можна тестувати безпосередньо (вони не мають таблиці для виконання асерцій) і не відображаються в інструментах data lineage. Ephemeral варто використовувати для внутрішньої допоміжної логіки, а view — для всього, що потребує незалежного тестування або моніторингу.
П: Поясніть різницю між source() та ref().
source() вказує на сирі таблиці, визначені у файлі sources.yml — це таблиці, якими dbt не управляє. ref() вказує на інші dbt-моделі. Обидві функції реєструють залежності у DAG, проте source() також дозволяє виконувати перевірки свіжості (dbt source freshness), чого ref() не підтримує. Використання source() для сирих таблиць і ref() для решти — це не рекомендація, а обов'язкова вимога, адже саме так dbt розрізняє те, чим він управляє, від того, чим ні.
Для ширшого набору питань зі співбесід з data engineering, включаючи теми на кшталт ETL vs ELT архітектури пайплайнів, модулі SharpSkill з основ dbt та просунутих dbt-патернів охоплюють ці концепції з інтерактивними вправами.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Висновки
- dbt трансформує сирі дані у сховищі через SQL SELECT-запити, які автоматично компілюються у DDL — пошарова структура staging/intermediate/mart забезпечує єдину відповідальність кожної моделі
- Функція
ref()є основою управління залежностями: вона розв'язує імена таблиць та будує DAG, що контролює порядок виконання - Інкрементальні матеріалізації зменшують витрати на великих таблицях, але потребують ретельної обробки
unique_key, NULL-значень та фільтраis_incremental() - Тестування повинно відповідати потоку даних — свіжість джерел, обмеження схеми на staging-рівні, референційна цілісність на intermediate-рівні, бізнес-асерції на рівні marts
- dbt Core v1.10 додає прапорець
--sampleдля швидших ітерацій, а Fusion Engine (на базі Rust, версія 2.0) тепер є стандартом у dbt Cloud - Питання на співбесідах щодо dbt зосереджені на діагностиці реальних збоїв (повна перебудова інкрементальних моделей, NULL-ключі, застарілі джерела), а не на визначеннях — практичний досвід роботи зі скомпільованим SQL та CI-пайплайнами важить більше за заучені відповіді
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Теги
Поділитися
Пов'язані статті

Apache Spark 4 у 2026 році: нові можливості, Structured Streaming та питання для співбесіди
Технічний огляд Apache Spark 4 з ANSI SQL, типом даних VARIANT, Real-Time Mode Streaming, Spark Connect та найважливішими питаннями для співбесіди на позиції Data Engineering.

25 найпоширеніших питань на співбесіді з Data Engineering у 2026 році
25 найпоширеніших питань на співбесіді з data engineering у 2026 році: SQL, data pipeline, ETL/ELT, Spark, Kafka, моделювання даних та проєктування систем з детальними відповідями.

ETL проти ELT у 2026: Архітектура пайплайнів даних
Порівняння ETL та ELT для сучасних пайплайнів даних. Архітектурні відмінності, компроміси продуктивності та застосування зі Snowflake, BigQuery і dbt.