В чём отличие dbt от хранимых процедур?

Ответ

dbt (Data Build Tool) и хранимые процедуры — это два принципиально разных подхода к трансформации данных в хранилище (DWH).

Аспект dbt (ELT-подход) Хранимые процедуры (ETL-подход)
Логика и версионирование Код (SQL + Jinja) хранится в Git. Легкое отслеживание изменений, code review, CI/CD. Код живет внутри БД. Версионирование и совместная разработка сложнее.
Модульность и зависимости Четкая модульность через ref('model_name'). dbt сам строит DAG зависимостей. Зависимости между процедурами часто неявные, требуют ручного управления.
Тестирование и документация Встроенные возможности: тесты на уникальность, not_null, свежесть данных. Автогенерация документации. Тестирование нужно организовывать вручную (отдельные скрипты, юнит-тесты).
Выполнение dbt генерирует и выполняет обычный SQL (CREATE TABLE AS SELECT ...). Прозрачно для оптимизатора БД. Выполняется процедурный код на SQL/PLpgSQL внутри БД. Может быть «черным ящиком».
Интеграция с оркестратором Идеально стыкуется с Airflow, Dagster (запуск dbt run как отдельной задачи). Оркестратор вызывает процедуру через CALL. Логика выполнения скрыта внутри БД.

Пример dbt-модели:

-- models/fct_orders.sql
{{ config(materialized='incremental') }}

SELECT
    o.order_id,
    o.customer_id,
    o.amount,
    c.customer_segment
FROM {{ ref('stg_orders') }} o
LEFT JOIN {{ ref('dim_customers') }} c USING (customer_id)
WHERE o.status = 'completed'
{% if is_incremental() %}
    AND o.order_date > (SELECT MAX(order_date) FROM {{ this }})
{% endif %}

В моей практике dbt обеспечивает лучшую управляемость, тестируемость и прозрачность пайплайнов данных для команды.

Ответ 18+ 🔞

Ну слушай, вот реально интересный вопрос — dbt против хранимок, это как два разных мира сталкиваются. Один — современный, с гитом и тестами, другой — старый добрый, но местами такой, что волосы дыбом встают.

dbt — это как умный, аккуратный чувак, который всё по полочкам разложил. Всё в гите, все изменения видны, откатиться можно, если что. Зависимости между моделями он сам выстраивает, как пазл собирает. А тесты... ёпта, это вообще песня! Накидал в конфиг, что поле не должно быть пустым, и всё — система сама будет материться, если данные кривые. Документация генерируется почти сама собой. И главное — он не выёбывается, а просто генерирует чистый SQL, который база и так схавает. Прозрачно, понятно.

А хранимые процедуры — это как дед в гараже, у которого всё работает, но разобраться может только он. Код где? Да внутри базы, блин! Попробуй там версионирование наладить — это ж пиздец, а не задача. Зависимости? А хрен их знает, какая процедура какую дергает, надо по коду ползать. Тестировать? Да пиши отдельные скрипты, выдумывай велосипед. И выполняется это всё как чёрный ящик — оркестратор дернул CALL, а дальше сиди и молись, чтобы не накрылось всё медным тазом.

Вот смотри на пример dbt-модели. Всё чётко, читаемо. Видно, откуда данные берутся (ref), видно, что это инкрементальная загрузка. Никакой магии, просто SQL.

-- models/fct_orders.sql
{{ config(materialized='incremental') }}

SELECT
    o.order_id,
    o.customer_id,
    o.amount,
    c.customer_segment
FROM {{ ref('stg_orders') }} o
LEFT JOIN {{ ref('dim_customers') }} c USING (customer_id)
WHERE o.status = 'completed'
{% if is_incremental() %}
    AND o.order_date > (SELECT MAX(order_date) FROM {{ this }})
{% endif %}

А теперь представь эту же логику в хранимой процедуре на каком-нибудь PL/pgSQL. Там на три листа кода, с переменными, циклами и кривыми исключениями. Потом её полгода поддерживать, и каждый раз чувствуешь, как терпения ноль ебать.

Итог-то какой? Если проект серьёзный, команда больше одного человека, и хочется спать спокойно — dbt рулит. Это управляемость, прозрачность и, блин, просто нормальная инженерная культура. Хранимки — они для каких-то точечных, специфичных задач, где без процедурной логики реально никуда. Но строить на них всю аналитическую платформу — это самоубийство, ей-богу. Сам через это проходил, больше не хочу.