open atlas
↑ К треку
Data engineering DATA · 02 · 01

ELT против ETL: где выполняется Transform и почему индустрия перевернулась

ETL трансформирует до загрузки в отдельном движке; ELT грузит сырьё в склад и трансформирует в SQL. Дешёвый колоночный compute и раздельные storage/compute перевернули дефолт — и перенесли стоимость на счёт склада.

DATA Junior ◷ 16 min
Уровень
ОсновыJuniorMiddleSenior

В понедельник тебе пишет финансовый аналитик: «Почему наш счёт за Snowflake на прошлой неделе подскочил на 40%?» Ничего не выкатывали — кроме изменения в пайплайне. Кто-то выставил dbt-модели full-refresh по умолчанию и поставил их по расписанию ежечасно. Каждый запуск пересканирует всю фактовую таблицу на 2 ТБ и пересобирает её с нуля. Трансформация корректна. Баг — это счёт. Это та самая «налоговая ставка ELT», о которой никто не предупредил: когда T делает склад, склад тарифицирует каждый байт, к которому ты прикоснулся.

К концу урока ты поймёшь, почему индустрия перешла от ETL к ELT, что на самом деле даёт воспроизводимость данных и как не платить за compute, который тебе не нужен.

Развилка пайплайна: где живёт T

Когда ты проектируешь дата-пайплайн, первый вопрос — не какой инструмент взять, а где выполняется трансформация. Именно от этого решения зависит, будет ли баг однострочным SQL-фиксом или неделей re-extract из источника, который, возможно, уже не держит нужные данные.

Оба паттерна перемещают данные из источников в склад. Единственная реальная разница — порядок средней буквы, и эта одна перестановка меняет всё, что идёт дальше.

ETL (extract, transform, load) родился, когда storage и compute были одной дорогой коробкой. Ты не мог позволить себе сгружать всё в склад, поэтому трансформировал сначала — в отдельном движке (Informatica, кластер Spark/Hadoop, Python-джоб) — чистил, джойнил, фильтровал и агрегировал, а потом грузил только отполированный результат. Склад видел только готовую таблицу.

ELT (extract, load, transform) переставляет два последних шага. Ты грузишь сырые исходные данные в склад первыми, нетронутыми, а потом трансформируешь их на месте в SQL. Трансформация больше не отдельная система — это запросы, выполняющиеся на том же движке, что хранит данные. dbt — доминирующий инструмент для «T»: версионируемые, протестированные, документированные SQL-модели вместо чёрного ящика-пайплайна.

Причина переворота индустрии архитектурная, а не модная. Snowflake и BigQuery разделяют storage и compute. Storage — это дешёвое объектное хранилище; compute — отдельный эластичный ресурс, который ты поднимаешь только когда выполняется запрос. Это полностью ломает старое ограничение — ты можешь позволить себе посадить сырьё, потому что хранить его почти ничего не стоит, а за compute платишь только когда реально трансформируешь.

Почему ELT победил: сырьё воспроизводимо

Самая глубокая причина, по которой ELT стал дефолтом, — не цена, а воспроизводимость (возможность переиграть). В ETL сырые исходные данные выбрасываются после трансформации; склад держит только трансформированный вывод. Поэтому когда (не если) ты находишь баг в трансформации — неверный ключ джойна, ошибку таймзоны, валюту, которую надо было конвертировать, — ты не можешь починить историю. Сырой ввод исчез. Приходится переэкстрагировать из источника, а источник мог измениться, заблокировать тебя по rate-limit или больше не держать старые строки.

В ELT сырьё живёт в складе постоянно. Баг трансформации — это однострочный SQL-фикс плюс перезапуск по данным, которые у тебя уже есть. Никакого re-extract. Это сердце medallion-архитектуры (трёхслойной схемы хранения данных): слой bronze из сырых, append-only (только дозапись, без изменения существующих строк) загруженных данных; слой silver из очищенных, приведённых, дедуплицированных таблиц; слой gold из готовых к бизнесу агрегатов и витрин. Каждый слой пересобираем из нижнего, а bronze пересобираем из источника, только если уж совсем нужно. Контракт такой: никогда не мутируй bronze, всегда трансформируй вперёд.

ИзмерениеETL (трансформ до загрузки)ELT (трансформ в складе)
Точность сырьяПотеряна — хранится только трансформированный выводСохранена — слой bronze воспроизводим
Починка бага трансформацииRe-extract из источника (может исчезнуть)Правишь SQL, перезапуск по имеющемуся сырью
Где тарифицируется computeОтдельный движок (твой кластер)Склад — каждый трансформ в счёте
Контроль PII / цены до загрузкиСильный — снять/замаскировать до посадкиСлабый — сырьё (вкл. PII) садится первым
Дисциплина схемыSchema-on-write (на загрузке)Schema-on-read (ты обеспечиваешь в silver)

Стоимость переезжает на счёт склада

ELT не делает трансформацию бесплатной — он переносит стоимость с CapEx-кластера, которым ты владел, на тарифицируемую OpEx-строку в счёте склада, и эта строка зверски чувствительна к тому, как ты пишешь SQL. Hook — каноничный провал: модель, материализованная как полная пересборка таблицы, поставленная часто по расписанию, сканирующая всё на каждом запуске. В Snowflake ты платишь за warehouse-секунду; в BigQuery — за просканированные байты. SELECT * по непартиционированной таблице на 2 ТБ, ежечасно, — это уже сам по себе четырёхзначный пункт месячного счёта.

Фикс — инкрементальные модели. Вместо пересборки всей таблицы ты обрабатываешь только новые или изменённые строки с прошлого запуска. В dbt это макрос is_incremental(), оборачивающий фильтр:

{% if is_incremental() %}
  where event_time >= (select max(event_time) from {{ this }})
{% endif %}

На первом запуске таблица строится полностью; на каждом следующем трогаются только строки новее текущего максимума. Ночной джоб, сканировавший 2 ТБ, теперь сканирует дельту за день — часто несколько ГБ — срезая и время выполнения, и тарифицируемые байты на один-два порядка. Когда ты создаёшь новую dbt-модель, базовая позиция такая: инкрементально по умолчанию, full refresh только когда меняется логика (dbt run --full-refresh), и отдельный warehouse на команду, чтобы тяжёлый трансформ никогда не голодил BI-дашборды на общем compute. Команды, забывающие auto-suspend на простаивающих warehouse, сливают кредиты за compute, который ничего не делает.

Почему это работает

«Schema-on-read» звучит как свобода, но это отложенный счёт. Schema-on-write в ETL отвергает кривую строку на загрузке — ты узнаёшь сразу. ELT с радостью садит что угодно в bronze; нарушение контракта всплывает позже, в silver, часто как тихий NULL или неверный джойн. ELT не убирает работу со схемой — он сдвигает её ниже по потоку и делает твоей задачей обеспечить её в тестах, а не задачей загрузчика.

Идемпотентность: повтор, который удваивает твои данные

Провал, от которого люди просыпаются ночью, — дублирование данных. EL-инструменты вроде Fivetran и Airbyte, и твои собственные загрузчики, повторяют при временном сбое — это корректное поведение. Но если загрузка не идемпотентна, повтор, перезапускающий частично-успешный батч, вставляет те же строки дважды. Теперь твой итог по выручке завышен, и дашборду никто не верит.

Лекарство — сделать загрузки и инкрементальные трансформации идемпотентными: запустить дважды даёт тот же результат, что запустить один раз. В инкрементальных моделях dbt это стратегия merge с unique_key:

{{ config(materialized='incremental', incremental_strategy='merge', unique_key='event_id') }}

На каждой строке merge обновляет, если unique_key уже существует, и вставляет, если нет — это upsert. Повтор того же батча обновляет строки на месте вместо дублирования. Ловушка: инкрементальная модель без unique_key и без фильтра is_incremental() тихо аппендит весь свой вывод на каждом запуске, поэтому она и дублирует, и пересканирует всё — худшее из двух миров. Microbatch-модели идут дальше, трактуя каждый временно́й батч как атомарную, независимо заменяемую единицу, поэтому упавший батч переигрывается чисто, не трогая соседей.

Выбери лучший вариант

Регулируемый финтех загружает платёжные события с номерами карт (PAN) и PII. Комплаенс запрещает сырым данным держателя карты вообще оказываться в аналитическом складе. Выбери паттерн.

Викторина

Ты находишь баг с таймзоной в трансформации, которая работала полгода. При ELT с medallion-архитектурой какой быстрый фикс?

Викторина

Инкрементальная dbt-модель настроена без unique_key и без фильтра is_incremental(). Что происходит на каждом запуске по расписанию?

Расставь шаги по порядку

Расставь стадии современного ELT-пайплайна от источника до дашборда:

  1. 1 Extract + Load: EL-инструмент (Fivetran/Airbyte) копирует сырые исходные данные в склад
  2. 2 Bronze: сырые, append-only посаженные данные, никогда не мутируются
  3. 3 Silver: очищенные, дедуплицированные, приведённые таблицы (dbt-модели, схема обеспечивается здесь)
  4. 4 Gold: готовые к бизнесу агрегаты и витрины
  5. 5 BI / дашборды читают из gold

Все пять стадий вместе образуют medallion-контракт: сырьё сохранено в bronze — поэтому каждый слой выше пересобираем. Без этого порядка, а конкретно без посадки сырья до трансформации, ты теряешь возможность переиграть историю при изменении логики — а это самая дорогостоящая потеря.

Вспомните перед уходом
  1. 01
    Объясни, почему индустрия перешла от ETL к ELT и что ты отдал в этом обмене.
  2. 02
    Повтор продублировал строки в фактовой таблице и завысил выручку. Какой дизайн это бы предотвратил и почему?
Итог

ETL и ELT отличаются только тем, где выполняется Transform, и эта одна перестановка решает цену, воспроизводимость и точность данных. ETL трансформирует в отдельном движке до загрузки и держит только отполированный вывод — сильно для снятия PII и контроля цены до посадки данных, но сырьё выброшено, поэтому баг трансформации означает re-extract из источника, которого может уже не быть. ELT грузит сырьё в склад первым и трансформирует в SQL (dbt), что облачное разделение storage и compute сделало дешёвым. Его решающее преимущество — воспроизводимость через medallion-паттерн: неизменный сырой bronze, очищенный silver, готовый к бизнесу gold, каждый пересобираем из нижнего. Цена в том, что compute трансформа теперь тарифицируется на счёте склада — поэтому идёшь инкрементально (обрабатываешь только дельту, а не полную пересборку) и идемпотентно (merge по unique_key) или получаешь взрыв трат и дублирующиеся строки на повторе. Выбирай ELT по умолчанию; тянись к ETL, когда жёсткое правило говорит, что сырая PII не должна касаться склада. Теперь, когда видишь скачок счёта за Snowflake после изменения в пайплайне, первый вопрос: не пересобирает ли модель всё по расписанию — и если да, где её инкрементальный фильтр?

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.