Ответ
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 рулит. Это управляемость, прозрачность и, блин, просто нормальная инженерная культура. Хранимки — они для каких-то точечных, специфичных задач, где без процедурной логики реально никуда. Но строить на них всю аналитическую платформу — это самоубийство, ей-богу. Сам через это проходил, больше не хочу.