dbt — это в первую очередь CLI-инструмент. Чтобы стать продуктивным, нужно знать примерно дюжину команд, понимать, какая что делает и в каком порядке их обычно дёргают. В этом уроке — карта повседневного арсенала junior analytics engineer.
Анатомия команды
Любая команда dbt имеет вид:
dbt <command> [global-options] [command-options]
Глобальные опции (работают почти везде):
--profiles-dir PATH— где искатьprofiles.yml(по умолчанию~/.dbt/)--project-dir PATH— корень проекта (по умолчанию текущая директория)--target NAME— какой output из profile использовать (dev,prod, …)--vars '{key: value}'— передать переменные модели--quiet/--debug— уровень логирования
Поэтому полная команда часто выглядит как dbt --debug run --select stg_orders --target dev. Чем больше проект, тем чаще ты будешь использовать флаги.
Сгруппированы по фазам жизни проекта: setup, build, observe, debug.
dbt debug — первое, что запускают
Когда что-то не работает — начинай отсюда. dbt debug проверяет три вещи: что dbt видит твой проект, что profiles.yml валиден и что dbt может подключиться к warehouse.
$ dbt debug
14:23:15 Running with dbt=1.10.2
14:23:15 dbt version: 1.10.2
14:23:15 python version: 3.11.7
14:23:15 python path: /Users/me/.venv/bin/python
14:23:15 os info: macOS-14.5
14:23:15 Using profiles dir at /Users/me/.dbt
14:23:15 Using profiles.yml file at /Users/me/.dbt/profiles.yml
14:23:15 Using dbt_project.yml file at /Users/me/jaffle_shop/dbt_project.yml
14:23:15 Configuration:
14:23:15 profiles.yml file [OK found and valid]
14:23:15 dbt_project.yml file [OK found and valid]
14:23:15 Required dependencies:
14:23:15 - git [OK found]
14:23:15 Connection:
14:23:15 database: jaffle_shop
14:23:15 schema: main
14:23:15 path: ./jaffle_shop.duckdb
14:23:15 Connection test: [OK connection ok]
14:23:15 All checks passed!
Если хотя бы одна строка вместо [OK ...] показывает [ERROR ...] — фикс начни здесь, в run/test пока бесполезно лезть.
dbt debug --config-dir выводит путь к profiles.yml. Полезно, когда есть несколько активных venv и не помнишь, какой профиль сейчас активен.
dbt deps — установка пакетов
Если у тебя в проекте есть packages.yml, перед первым запуском нужно его подтянуть:
$ dbt deps
14:25:01 Installing dbt-labs/dbt_utils
14:25:02 Installed from version 1.3.0
14:25:02 Installing calogica/dbt_expectations
14:25:02 Installed from version 0.10.4
Пакеты складываются в dbt_packages/ в корне проекта. Эта папка в .gitignore — её локально регенерируешь после каждого git pull, который тронул packages.yml.
Самая частая ошибка junior: меняют packages.yml, не запускают dbt deps, потом удивляются «macro dbt_utils.star not defined».
dbt seed — CSV в таблицы
Сидирование (dbt seed) превращает CSV из папки seeds/ в таблицы в warehouse. Используется для маленьких справочников: коды стран, currency-маппинги, тестовые фикстуры.
$ dbt seed
14:27:14 Running with dbt=1.10.2
14:27:14 Found 2 seeds, 0 models, 0 tests, 0 sources, 0 exposures, 0 metrics
14:27:14
14:27:15 Concurrency: 4 threads (target='dev')
14:27:15
14:27:15 1 of 2 START seed file main.country_codes ... [RUN]
14:27:15 1 of 2 OK loaded seed file main.country_codes ... [INSERT 250 in 0.12s]
14:27:15 2 of 2 START seed file main.products_catalog ... [RUN]
14:27:15 2 of 2 OK loaded seed file main.products_catalog ... [INSERT 12 in 0.04s]
14:27:15
14:27:15 Finished running 2 seeds in 0 hours 0 minutes and 0.23 seconds (0.23s).
14:27:15 Completed successfully
dbt seed использует full-refresh по умолчанию — то есть DROP TABLE + CREATE TABLE каждый раз. Это нормально для маленьких сидов. Если у тебя сид >5 МБ — это сигнал, что данные надо было класть в source, а не в git.
dbt run — материализация моделей
dbt run берёт все модели в models/, компилирует Jinja в SQL и выполняет каждую в warehouse:
$ dbt run
14:30:42 Running with dbt=1.10.2
14:30:42 Found 8 models, 0 tests, 2 sources, 0 exposures, 0 metrics
14:30:42
14:30:42 Concurrency: 4 threads (target='dev')
14:30:42
14:30:42 1 of 8 START sql view model main.stg_jaffle__customers ... [RUN]
14:30:42 2 of 8 START sql view model main.stg_jaffle__orders ... [RUN]
14:30:42 3 of 8 START sql view model main.stg_jaffle__order_items ... [RUN]
14:30:42 4 of 8 START sql view model main.stg_jaffle__payments ... [RUN]
14:30:42 1 of 8 OK created sql view model main.stg_jaffle__customers ... [OK in 0.08s]
14:30:42 2 of 8 OK created sql view model main.stg_jaffle__orders ... [OK in 0.09s]
14:30:42 3 of 8 OK created sql view model main.stg_jaffle__order_items ... [OK in 0.08s]
14:30:42 4 of 8 OK created sql view model main.stg_jaffle__payments ... [OK in 0.07s]
14:30:42 5 of 8 START sql view model main.int_order_items_pivoted ... [RUN]
14:30:42 5 of 8 OK created sql view model main.int_order_items_pivoted ... [OK in 0.11s]
14:30:42 6 of 8 START sql table model main.customers ... [RUN]
14:30:42 7 of 8 START sql table model main.orders ... [RUN]
14:30:42 8 of 8 START sql table model main.revenue_daily ... [RUN]
14:30:42 6 of 8 OK created sql table model main.customers ... [OK in 0.32s]
14:30:42 7 of 8 OK created sql table model main.orders ... [OK in 0.41s]
14:30:42 8 of 8 OK created sql table model main.revenue_daily ... [OK in 0.28s]
14:30:43
14:30:43 Finished running 5 view models, 3 table models in 0 hours 0 minutes and 1.49 seconds (1.49s).
14:30:43 Completed successfully
14:30:43
14:30:43 Done. PASS=8 WARN=0 ERROR=0 SKIP=0 TOTAL=8
Несколько важных моментов:
- Модели бегут параллельно до
threadsштук одновременно (в примере 4). Параллелизм ограничен только зависимостями DAG. - В одном
dbt runмодели бегут в порядке топологической сортировки: сначала staging, потом intermediate, потом marts. - Если одна модель упала — её downstream-зависимости пропускаются (
SKIP), а остальные ветки DAG продолжают.
Важно: dbt run не запускает тесты. Если хочешь и материализовать, и тестировать одной командой — это dbt build.
dbt test — запуск тестов
dbt test запускает все тесты, описанные в YAML (generic) и в tests/ (singular). По дефолту тесты ничего не материализуют — они компилируются в SELECT ... FROM ... запросы, которые должны вернуть ноль строк. Если запрос вернул хоть одну — тест провалился.
$ dbt test
14:32:18 Running with dbt=1.10.2
14:32:18 Found 8 models, 14 tests, 2 sources, 0 exposures, 0 metrics
14:32:18
14:32:18 1 of 14 START test not_null_customers_customer_id ... [RUN]
14:32:18 1 of 14 PASS not_null_customers_customer_id ... [PASS in 0.04s]
14:32:18 2 of 14 START test unique_customers_customer_id ... [RUN]
14:32:18 2 of 14 PASS unique_customers_customer_id ... [PASS in 0.03s]
...
14:32:19 Finished running 14 tests in 0 hours 0 minutes and 1.12 seconds (1.12s).
14:32:19
14:32:19 Done. PASS=14 WARN=0 ERROR=0 SKIP=0 TOTAL=14
dbt test --select customers — запустит только тесты на модели customers. dbt test --select source:jaffle — только тесты на source-таблицы.
dbt build — всё за один проход
dbt build — это композит: он запускает в правильном порядке seed -> snapshot -> run -> test, с одним важным правилом: если модель упала или её upstream-тест провалился — все downstream-модели пропускаются.
$ dbt build
14:35:01 Concurrency: 4 threads (target='dev')
14:35:01
14:35:01 1 of 23 START seed file main.country_codes ... [PASS in 0.12s]
14:35:01 2 of 23 START seed file main.products_catalog ... [PASS in 0.04s]
14:35:01 3 of 23 START sql view model main.stg_jaffle__customers ... [OK in 0.08s]
14:35:01 4 of 23 START test not_null_stg_jaffle__customers_customer_id ... [PASS in 0.04s]
14:35:01 5 of 23 START sql view model main.stg_jaffle__orders ... [OK in 0.09s]
14:35:01 6 of 23 START test not_null_stg_jaffle__orders_order_id ... [FAIL in 0.05s]
14:35:01 7 of 23 SKIP relation main.customers ... [SKIP]
14:35:01 8 of 23 SKIP relation main.orders ... [SKIP]
...
14:35:01 Done. PASS=20 WARN=0 ERROR=1 SKIP=2 TOTAL=23
Заметь: stg_jaffle__orders материализовалась, но тест not_null_order_id провалился — и downstream-модели customers и orders были пропущены, не запущены вообще. Это и есть «short-circuit upstream failures», главная фича dbt build.
В production CI/CD используют только dbt build, никогда dbt run + dbt test отдельно. Причина: если между ними упасть, CI зелёный по run, но даты грязные.
dbt compile — посмотреть SQL без запуска
dbt compile берёт твои Jinja-модели, разворачивает {% %}, {{ ref() }}, {{ source() }} в готовый SQL и пишет в target/compiled/. Не запускает ничего в warehouse.
$ dbt compile --select customers
14:40:11 Found 8 models, ...
14:40:11 Concurrency: 4 threads
14:40:11
14:40:11 1 of 1 OK compiled customers ... [OK in 0.02s]
14:40:11 Finished compiling 1 model in 0.45s
Теперь в target/compiled/jaffle_shop/models/marts/customers.sql лежит готовый SQL. Это главный инструмент дебага — открываешь файл, копируешь SQL в duckdb shell или клиент warehouse, прогоняешь руками, видишь точно, что dbt отправил.
dbt show — превью без материализации
dbt show --select customers компилирует модель, оборачивает её в SELECT * FROM (...) LIMIT 5 и выполняет в warehouse, выводя результат прямо в терминал:
$ dbt show --select customers --limit 3
14:42:08 Previewing node 'customers':
| customer_id | first_name | last_name | total_spend_cents |
|-------------|------------|-----------|-------------------|
| 1 | Anna | Petrova | 12450 |
| 2 | Boris | Ivanov | 8900 |
| 3 | Carla | Smith | 15200 |
В отличие от dbt run, результат не материализуется в warehouse. Полезно когда хочешь быстро проверить «а что вообще модель сейчас выдаёт?», не пересоздавая таблицу.
--inline "SELECT ..." позволяет показать произвольный SQL без модели:
$ dbt show --inline "SELECT count(*) FROM {{ ref('customers') }}"
dbt list — какие узлы есть в проекте
dbt list (или dbt ls) перечисляет узлы DAG, удовлетворяющие селектору. Без аргументов — все:
$ dbt list
jaffle_shop.staging.stg_jaffle__customers
jaffle_shop.staging.stg_jaffle__orders
jaffle_shop.staging.stg_jaffle__order_items
jaffle_shop.staging.stg_jaffle__payments
jaffle_shop.intermediate.int_order_items_pivoted
jaffle_shop.marts.customers
jaffle_shop.marts.orders
jaffle_shop.marts.revenue_daily
С селектором — только подмножество:
$ dbt list --select tag:daily
jaffle_shop.marts.revenue_daily
$ dbt list --select customers+
jaffle_shop.marts.customers
Очень полезно для CI: dbt list --select state:modified+ покажет, что именно изменилось в PR.
dbt docs generate и dbt docs serve
dbt docs generate собирает target/catalog.json и target/manifest.json — это метаданные о всех моделях, колонках, типах. Затем dbt docs serve запускает локальный веб-сервер с интерактивной документацией:
$ dbt docs generate
$ dbt docs serve --port 8080
14:45:13 Serving docs at http://localhost:8080/
14:45:13 Press Ctrl+C to exit
Открывается lineage-граф со всеми связями ref() и source(). Junior часто запускают serve без generate — получают пустую страницу. Always generate first.
dbt clean — снести target
dbt clean удаляет target/ и dbt_packages/. Это нужно если:
- что-то странное в кешированных артефактах (редко)
- хочешь форсировать
dbt depsзаново - освободить место на диске
$ dbt clean
14:47:02 Checking target/...
14:47:02 deleted: target/
14:47:02 Checking dbt_packages/...
14:47:02 deleted: dbt_packages/
dbt source freshness — проверка свежести источников
Если у тебя в sources.yml настроены freshness: warn_after / error_after, эта команда сравнивает max(loaded_at_field) с текущим временем:
$ dbt source freshness
14:50:14 1 of 4 START freshness of jaffle.customers ... [RUN]
14:50:14 1 of 4 PASS freshness of jaffle.customers ... [PASS in 0.05s]
14:50:14 2 of 4 START freshness of jaffle.orders ... [RUN]
14:50:14 2 of 4 WARN freshness of jaffle.orders ... [WARN in 0.04s]
14:50:14 3 of 4 START freshness of jaffle.order_items ... [RUN]
14:50:14 3 of 4 ERROR STALE freshness of jaffle.order_items ... [ERROR STALE in 0.04s]
WARN означает превышен warn_after, ERROR STALE — превышен error_after. В CI после dbt source freshness обычно ставят dbt build, и если источники протухли — билд не запускают.
dbt run-operation — позвать макрос вручную
Иногда нужно выполнить кусок SQL/Jinja, не привязанный к модели. Например, GRANT SELECT после деплоя или VACUUM. Это делается через макрос + dbt run-operation:
$ dbt run-operation grant_select_on_marts --args '{role: "analyst"}'
14:53:02 Running with dbt=1.10.2
14:53:02 GRANT SELECT ON main.customers TO analyst;
14:53:02 GRANT SELECT ON main.orders TO analyst;
Макрос написан в macros/grant_select_on_marts.sql. Подробнее про макросы — в модуле 11.
dbt retry — продолжить с места падения
Если dbt build упал на 50-й из 200 моделей, не хочется запускать всё заново. dbt retry смотрит в target/run_results.json, находит все узлы со статусом error или skipped, и запускает только их + всё, что ниже по DAG:
$ dbt build
... 50 models OK, 1 ERROR (stg_orders), 149 SKIP ...
$ dbt retry
14:55:01 Retrying 150 nodes from previous run
14:55:01 1 of 150 START sql view model main.stg_orders ... [OK in 0.08s]
14:55:01 ... 149 more ...
14:55:02 Done. PASS=150 WARN=0 ERROR=0 SKIP=0 TOTAL=150
Гениально экономит время на больших проектах. Особенно при flaky-warehouse, когда падение было сетевое и не повторится.
Попробуй сам
-
В терминале с активным dbt-проектом запусти подряд:
dbt debug dbt list dbt list --resource-type test dbt compile --select customersПосмотри, что появилось в
target/compiled/. -
Сломай одну staging-модель (например, добавь
SELECT * FORM ...опечатка). Запустиdbt build. Посмотри в выводе, чтоSKIPпоявился на downstream. Затем исправь опечатку и запустиdbt retry. -
Запусти
dbt docs generate && dbt docs serve --port 8080. Откройhttp://localhost:8080, найди lineage-граф.
Чек-лист
- Setup:
dbt debug->dbt deps->dbt seed. - Build day-to-day:
dbt build --select <something>. - Production CI: всегда
dbt build, никогдаdbt run + dbt testотдельно. - Дебаг:
dbt compile --select model_name, откройtarget/compiled/.../model_name.sql. - Превью:
dbt show --select model_name --limit 10. - Catalog:
dbt docs generateПЕРЕДdbt docs serve. - Recovery:
dbt retryпосле частичного падения. - Freshness:
dbt source freshnessв начале CI-пайплайна.