В предыдущем уроке мы разобрались, почему ETL появился именно таким — он отражает экономику 1990-х, где дорогим был DWH, а дешёвым — отдельный ETL-сервер. В 2010-х произошла инверсия: облачные хранилища типа Snowflake и BigQuery начали продавать compute и storage по отдельности, дешевле и эластичнее. Если железо вдруг перестало быть бутылочным горлышком, зачем выносить трансформации наружу?
Так появился ELT — Extract, Load, Transform. Тот же набор букв, но порядок другой, и от перестановки этих слагаемых меняется почти всё.
Что значит каждая буква
ELT — это Extract, Load, Transform. То есть данные сначала извлекают из источника, сразу же загружают в DWH в сыром виде, и только потом трансформируют — уже внутри хранилища, обычно через SQL.
Сырые данные сначала улетают в DWH, и уже там в чистом SQL-окружении превращаются в витрины. Отдельного ETL-сервера нет.
Заметь главное: в ELT трансформация живёт внутри DWH. Тебе не нужен отдельный сервер с Informatica. Достаточно SQL и движка, который этот SQL выполняет.
Почему появился ELT
ELT — это технологический ответ на изменение экономики. Несколько ключевых сдвигов произошли в районе 2010-2015 годов:
Облачные DWH разделили compute и storage. Snowflake первым массово показал модель, где можно купить хранилище отдельно (дёшево) и compute отдельно (по требованию, эластично). BigQuery и Redshift пошли по тому же пути. Это значит, что хранить сырьё стало почти бесплатно по сравнению с эпохой on-premise Teradata.
Compute стал эластичным. Если нужно прогнать тяжёлую трансформацию ночью — можно временно поднять кластер побольше и тут же его погасить. В мире Informatica это означало «купить более мощный сервер на 5 лет».
SQL-движки сильно поумнели. Современные columnar-движки (Snowflake, BigQuery, ClickHouse, Redshift) умеют выполнять сложные join’ы и оконные функции на терабайтах за секунды-минуты. То, для чего раньше требовался специальный ETL-движок, теперь чистый SQL.
В этом мире вопрос «куда вынести трансформации» начал звучать наивно. Их не нужно никуда выносить — они и так бегут на дешёвом эластичном compute прямо там, где лежат данные.
ELT — это не магия и не «золотая пуля». Это следствие конкретного экономического сдвига: облачные DWH сделали хранение почти бесплатным, а compute — эластичным. Без этого ELT бы не работал — на on-premise Teradata 2005 года залить сырьё было физически некуда.
Преимущества ELT
Сырые данные сохраняются. Главное преимущество. Если завтра аналитик попросит другую агрегацию или другой фильтр — не нужно идти к источнику, делать новый extract, ждать его выгрузку часами. Сырьё уже в DWH, новый запрос пишется и выполняется за минуты.
SQL — стандарт. В ETL логика была заперта в проприетарном GUI или специфичном DSL. В ELT почти всё пишется на SQL, который знают аналитики, дата-инженеры, иногда даже бизнес-пользователи. Это резко расширяет пул людей, способных читать и модифицировать пайплайны.
Git, code review, тесты. Раз трансформации — это SQL-файлы, их можно положить в git, прогонять через pull request, покрывать тестами через dbt. Этого почти не было в мире Informatica.
Эластичный compute. Тяжёлая трансформация ночью — поднял Snowflake warehouse XL, прогнал, выключил. Платишь только за минуты работы. Никаких лицензий на 5 лет вперёд.
Lineage и observability. Современные ELT-инструменты автоматически строят граф зависимостей между моделями — кто откуда читает, кто куда пишет. В Informatica это нужно было поддерживать руками.
Слева классическая схема с тяжёлым ETL-сервером и тонким DWH. Справа толстый DWH, в котором всё, и тонкий слой extract+load.
Типичный ELT-пайплайн
Чтобы было совсем конкретно, посмотрим, как выглядит пайплайн «выгрузить заказы из Postgres продакшена в Snowflake и построить витрину» в ELT-стиле.
Extract+Load. Запускается dlt-скрипт или Fivetran-коннектор, который читает таблицу orders из продакшена и пишет её в Snowflake в схему raw.production_orders — один к одному, без преобразований. Расписание — каждый час.
Transform. Дальше работает dbt. Он берёт raw.production_orders, применяет SQL-трансформации:
-- models/staging/stg_orders.sql
SELECT
id::INT AS order_id,
customer_id::INT AS customer_id,
amount::DECIMAL(18, 2) AS order_amount,
status AS order_status,
created_at::TIMESTAMP_NTZ AS ordered_at
FROM {{ source('raw', 'production_orders') }}
WHERE status NOT IN ('test', 'cancelled')
Это staging-модель: типизировала, чуть-чуть отфильтровала, переименовала колонки. Дальше идут модели уровня выше — mart’ы, агрегаты, fact и dimension таблицы.
-- models/marts/fct_daily_orders.sql
SELECT
DATE(ordered_at) AS order_date,
customer_id,
COUNT(*) AS orders_count,
SUM(order_amount) AS total_amount
FROM {{ ref('stg_orders') }}
GROUP BY 1, 2
Запись ref('stg_orders') обёрнутая в Jinja-теги — это макрос dbt, который превращается в полное имя таблицы и автоматически строит граф зависимостей. dbt знает, что fct_daily_orders зависит от stg_orders, и не пытается их пересчитать в неправильном порядке.
Весь этот SQL лежит в git, проходит через pull request, имеет тесты на колонки (unique, not_null, кастомные), и при деплое запускается через dbt run — обычная команда в CI/CD.
Минусы ELT
ELT не идеален, и важно их понимать, чтобы не разочароваться:
Compute счёт может удивить. В Snowflake/BigQuery платишь за каждую секунду работы. Если кто-то написал тяжёлую модель, которая каждые 15 минут сканит миллиард строк — счёт в конце месяца может быть болезненный. В Informatica лицензия фиксированная.
PII попадает в DWH. Если в источнике есть телефоны, email, паспорта — в ELT они приедут в DWH в сыром виде. Нужны отдельные практики: маскинг на уровне колонок, row-level security, отдельные схемы с ограниченным доступом. Это решаемо, но требует дисциплины.
Source-system coupling. Если в источнике поменяется схема (добавили колонку, переименовали поле) — это сразу всплывёт в raw-слое и сломает downstream. Нужны schema contracts и monitoring.
В реальных компаниях редко встречается чистый ELT или чистый ETL. Чаще всего это гибрид: для PII-данных есть лёгкий transform до load, для всего остального — ELT по умолчанию. Главное — понимать, какой шаблон что даёт, и осознанно выбирать.
Попробуй сам
Подумай о пайплайне, который ты видел или о котором слышал. Если он построен на SQL внутри Snowflake/BigQuery поверх dbt — это ELT. Если он живёт в Informatica/SSIS и пишет только агрегаты — это ETL. А если данные идут через Kafka и трансформируются Spark Streaming на лету, ещё до Snowflake — это уже ни то, ни другое, это streaming-пайплайн (про него в следующем модуле). Привыкай классифицировать пайплайны по этим осям — это базовый язык DE.