Learning Platform
Глоссарий Troubleshooting
Урок 19.02 · 20 мин
Начальный
Debuggingdbt debugdbt compiledbt showWorkflow

dbt предоставляет три команды специально для дебага. Каждая отвечает на свой вопрос:

  • dbt debug — «у меня вообще запускается?» (соединение, профиль, конфиг)
  • dbt compile — «какой SQL dbt сгенерирует?» (без запуска в БД)
  • dbt show — «что эта модель сейчас бы вернула?» (запуск превью, без материализации)

Из этой триады junior начинают использовать compile после первой реальной ошибки, debug — после первой проблемы с подключением, show — после третьего «а что в этой модели сейчас?».

Три команды — три уровня проблемы

Когда что-то не работает, идёшь сверху вниз: сначала проверь соединение (debug), потом SQL (compile), потом данные (show).

dbt debugУровень 1: соединение и конфиг
dbt compileУровень 2: финальный SQL после Jinja
dbt showУровень 3: реальное превью без материализации

dbt debug — диагностика окружения

Запускают первым делом после pip install, после git clone, после смены ветки, после правки profiles.yml. Команда проверяет:

  1. dbt-core установлен и какой версии
  2. python-окружение
  3. dbt_project.yml найден и валиден
  4. profiles.yml найден и валиден
  5. Профиль из dbt_project.yml существует в profiles.yml
  6. Адаптер установлен (например, dbt-duckdb)
  7. Соединение к 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!

Каждый блок — независимая проверка. Если есть [ERROR ...] — фикс этого блока перед движением дальше.

Типичные провалы

profiles.yml file [ERROR not found]

dbt ищет profiles.yml в ~/.dbt/ или в каталоге, указанном через DBT_PROFILES_DIR env var, или через флаг --profiles-dir. Если файла нет — создай:

mkdir -p ~/.dbt
nano ~/.dbt/profiles.yml

И заполни шаблоном для своего адаптера (см. модуль 3-setup).

Profile not found: jaffle_shop

В dbt_project.yml стоит profile: jaffle_shop, но в profiles.yml такого ключа верхнего уровня нет. Проверь, что они совпадают по имени.

Connection test: [ERROR ...]

База недоступна. Для DuckDB причины:

  • неверный path (относительный путь от текущей директории, не от проекта)
  • файл .duckdb повреждён (попробуй удалить и создать заново)
  • DuckDB занят другим процессом (single-writer per file)

Для облачных warehouses:

  • неверные креды (env_var указывает на пустую переменную)
  • VPN/IP whitelist
  • неправильный регион/host

dbt debug --connection — пропустить проверки файлов, тестировать только соединение. Полезно когда уже знаешь, что конфиг валидный, и хочешь быстро проверить «база живая?».

dbt debug --config-dir — печатает путь к profiles.yml. Полезно когда есть несколько venv с разными конфигами.

TIP

Завести алиас в shell: alias dd='dbt debug --connection'. Каждый раз перед началом работы — dd. 5 секунд экономят часы.


dbt compile — финальный SQL без запуска

dbt compile развернёт Jinja и положит финальный SQL в target/compiled/<project>/.../<model>.sql. В warehouse при этом не обращается — это чисто текстовая трансформация.

$ dbt compile --select customers
14:30:11  Running with dbt=1.10.2
14:30:11  Found 8 models, 14 tests, ...
14:30:11  Concurrency: 4 threads
14:30:11
14:30:11  1 of 1 OK compiled customers ... [OK in 0.02s]
14:30:11  Finished compiling 1 model in 0 hours 0 minutes and 0.45 seconds

После этого в target/compiled/jaffle_shop/models/marts/customers.sql лежит готовый SQL. Открой в редакторе:

-- было в models/marts/customers.sql:
-- select c.customer_id, count(o.order_id) as order_count
-- from {{ ref('stg_jaffle__customers') }} c
-- left join {{ ref('stg_jaffle__orders') }} o on c.customer_id = o.customer_id
-- group by c.customer_id

-- стало в target/compiled/...:
select c.customer_id, count(o.order_id) as order_count
from "jaffle_shop"."main"."stg_jaffle__customers" c
left join "jaffle_shop"."main"."stg_jaffle__orders" o on c.customer_id = o.customer_id
group by c.customer_id

{{ ref('stg_jaffle__customers') }} развернулось в "jaffle_shop"."main"."stg_jaffle__customers" — фактическое имя таблицы, которое dbt отправит в БД.

Зачем это нужно

  1. Дебаг ошибок SQL. Скопируй SQL в DuckDB shell, прогоны вручную, увидь точную ошибку с line:column.

  2. Понять, что Jinja развернулось правильно. Если у тебя есть условие {% if target.name == 'prod' %} — посмотри, что в target.name сейчас, какая ветка выбралась.

  3. Code review без запуска dbt. В PR можно приложить target/compiled/ и review-er увидит финальный SQL без локального запуска.

  4. Производительность. Скопировать SQL в EXPLAIN ANALYZE и посмотреть план запроса в warehouse.

dbt compile --select +my_model — скомпилирует модель и весь её upstream. dbt compile без флагов — всё в проекте, что бывает удобно для статического анализа.

dbt compile --inline

Можно скомпилировать произвольную Jinja-строку, не привязанную к файлу:

$ dbt compile --inline "SELECT count(*) FROM {{ ref('customers') }}"
14:32:15  Compiled inline node
14:32:15  
14:32:15  SELECT count(*) FROM "jaffle_shop"."main"."customers"

Полезно для быстрых проверок: «как именно ref() этой модели развернётся?»


dbt show — превью без материализации

dbt show отличается от compile тем, что он выполняет SQL в warehouse — но не материализует таблицу, а просто выбирает первые N строк и печатает в терминал:

$ dbt show --select customers --limit 5
14:35:01  Previewing node 'customers':
| customer_id | first_name | last_name | order_count |
|-------------|------------|-----------|-------------|
|           1 | Anna       | Petrova   |           3 |
|           2 | Boris      | Ivanov    |           1 |
|           3 | Carla      | Smith     |           5 |
|           4 | Dmitry     | Volkov    |           2 |
|           5 | Elena      | Sidorova  |           0 |

Внутри dbt оборачивает скомпилированный SQL в SELECT * FROM (...) LIMIT 5 и шлёт в warehouse. Никаких CREATE TABLE / CREATE VIEW — материализации не происходит.

--limit N — кол-во строк. По умолчанию 5.

Зачем

  1. Быстро проверить, что модель вообще что-то возвращает, не пересоздавая таблицу.
  2. Локально итерировать на staging-моделях: пишешь SQL, dbt show — видишь результат. Не нужно полное dbt run, который для view ещё ладно, для table — дорого.
  3. Дебаг с конкретными данными: модель возвращает «не то» — show покажет, что именно.

dbt show --inline

То же, что compile —inline, но с выполнением:

$ dbt show --inline "SELECT count(*) FROM {{ ref('customers') }}" 
14:37:02  Previewing inline node:
| count_star() |
|--------------|
|         1000 |

Удобный способ быстро проверить, сколько строк сейчас в модели, не открывая SQL-клиент.

Caveats

  • dbt show не подходит для тяжёлых моделей — он всё-таки выполняет SQL. Если модель с 10 джойнами и группировкой по 1B строк, превью займёт минуты. В таких случаях надёжнее dbt compile + ручной EXPLAIN.
  • Результат печатается в текстовый формат — для серьёзного анализа лучше открыть BI или SQL-клиент.

Идеальный workflow дебага

Сценарий: ты получил ошибку в dbt run:

Error in model orders (models/marts/orders.sql)
  Database Error in model orders
  Catalog Error: Table "stg_jaffle__orders" does not exist!
  Did you mean "main.stg_jaffle__orders"?

Шаг 1: dbt debug

Проверь, что окружение в порядке:

$ dbt debug --connection
14:40:01  Connection test: [OK]
14:40:01  All checks passed!

OK, не в этом дело. Идём дальше.

Шаг 2: dbt compile

Скомпилируй проблемную модель и посмотри финальный SQL:

$ dbt compile --select orders
14:40:15  Compiled orders ...

Открой target/compiled/jaffle_shop/models/marts/orders.sql:

select o.*, c.customer_name
from stg_jaffle__orders o  -- БАГ! Должно быть {{ ref('stg_jaffle__orders') }}
left join {{ ref('stg_jaffle__customers') }} c on o.customer_id = c.customer_id

— ага, кто-то написал прямое имя таблицы вместо ref(). Это и есть «hardcoded table name» антипаттерн из модуля 4. Меняем:

from {{ ref('stg_jaffle__orders') }} o

Шаг 3: dbt show

После фикса прогоним превью:

$ dbt show --select orders --limit 5
14:42:08  Previewing node 'orders':
| order_id | customer_id | customer_name | total_cents |
|----------|-------------|---------------|-------------|
|        1 |           1 | Anna Petrova  |        2400 |
...

Работает. Теперь dbt run --select orders для реальной материализации.

Этот цикл debug -> compile -> show -> run — главный mental loop junior в dbt.


Когда dbt compile не помогает

Иногда баг не в SQL, а в Jinja-логике, которая ещё не дошла до компиляции. Тогда dbt compile падает раньше, чем что-то напишет в target/.

Типичные случаи:

  • Macro определён, но dbt deps не запускали — пакет физически не на диске.
  • Опечатка в имени макроса: {{ dbt_utils.starr(...) }} (две r) — Jinja не может найти.
  • {% if execute %} вокруг run_query — если попадаешь на parse phase, query не запускается; об этом — модуль 10.
  • Конфиг-блок в неправильном месте (после select — игнорируется).

В этих случаях смотри logs/dbt.log — об этом следующий урок.


Попробуй сам

  1. Сломай профиль: переименуй profiles.yml -> profiles.yml.bak. Запусти dbt debug. Прочитай ошибку. Восстанови.

  2. В модели customers.sql намеренно опечатайся в имени макроса: вместо {{ ref('stg_jaffle__customers') }} напиши {{ rref('stg_jaffle__customers') }}. Запусти dbt compile --select customers. Прочитай ошибку. Исправь.

  3. Запусти dbt show --inline "SELECT now(), {{ target.name }}, {{ target.schema }}". Посмотри, что развернулось.

  4. Запусти dbt show --select stg_jaffle__orders --limit 3. Сравни вывод с dbt run --select stg_jaffle__orders — где материализация и где её нет.


Чек-лист

  • dbt debug — первый шаг при любой проблеме. Проверяет окружение и соединение.
  • dbt debug --connection — быстрый тест только подключения.
  • dbt compile --select <model> — финальный SQL в target/compiled/. Открой и копируй в SQL-клиент.
  • dbt compile --inline "..." — компиляция произвольной строки.
  • dbt show --select <model> --limit N — превью результата без материализации.
  • dbt show --inline "..." — выполнение произвольной строки и вывод результата.
  • Идеальный workflow: debug -> compile -> show -> run. Не пропускай шаги.
  • Если compile сам падает — смотри logs/dbt.log (следующий урок).
store_failures: дебаг через audit-таблицы
Проверка знанийKnowledge check
Аналитик пишет: 'Я добавил макрос get_currency_symbol в macros/utils.sql, использую {{ get_currency_symbol("USD") }} в модели. dbt run падает: undefined macro. dbt compile тоже падает. dbt debug говорит OK'. Какой алгоритм проверки и какие 4 наиболее вероятных причины?
ОтветAnswer
dbt debug проходит — значит окружение и соединение в порядке. dbt compile падает на этапе парсинга Jinja, до запроса в БД. Возможные причины: 1) Файл macros/utils.sql существует, но макрос внутри назван иначе (например, currency_symbol без get_) — попроси показать содержимое файла, проверь {% macro имя_функции(...) %}. 2) Файл не в директории, объявленной в dbt_project.yml как macro-paths (по умолчанию ['macros'], но если кто-то изменил — могло потеряться). 3) В dbt_project.yml неправильно сконфигурирован macro-paths, и dbt не видит файл. 4) Опечатка в вызове: get_currency_symbol vs get_currency_symbool. 5) Макрос находится в пакете (например, в dbt_utils-форке), а dbt deps не запускали — dbt_packages/ пуста. Шаг проверки: dbt list --resource-type macro --select my_macro_name — если нашёл, имя верное и dbt его видит, проблема в вызове. Если не нашёл — файла нет или путь не тот.

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

Результат: 0 из 0
Прикладной
Вопрос 1 из 6. Чем dbt debug отличается от dbt compile, и в каком порядке их применять при дебаге?

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

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

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

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