В предыдущих уроках мы изучили классические incremental-стратегии: append, delete+insert, merge. У всех есть общая особенность: дельта определяется через сравнение с уже существующей таблицей (типичный WHERE updated_at > (SELECT MAX(...) FROM {'{{'}'} this {'}}'})).
В dbt 1.9 появилась новая стратегия — microbatch. Она работает иначе: процессит данные порциями по времени (batches). Это особенно полезно для backfill, restating исторических данных, и для случаев, когда нужно явное окно обработки.
На junior-курсе мы дадим intro: концепт, основные параметры, ограничения dbt-duckdb. На middle-уровне будем работать глубже.
Зачем microbatch появился
Классический incremental с WHERE updated_at > max(...) хорош для простого добавления свежих данных. Но он плохо подходит для:
1. Backfill истории. Хочешь пересчитать историю за конкретный период (например, июнь 2024). С классическим incremental это сложно — приходится делать —full-refresh с фильтром в SQL.
2. Restating данных. Источник перезаписал данные за прошлый месяц. Нужно перезалить эти данные в incremental-таблицу. С классическим — снова —full-refresh.
3. Failure recovery. dbt run упал на полпути. Нужно повторить только не выполненные дни. С классическим — нельзя выборочно.
4. Параллельная обработка. На больших данных хочется делать backfill параллельно по дням, не последовательно.
Microbatch решает все эти проблемы через явное окно времени для каждой партии.
Концепт: event_time + batch_size
Базовая идея: каждая инкрементальная партия — это один временной интервал. Размер интервала задаётся batch_size (day, hour, month). Колонка event_time определяет, к какому интервалу относится каждая строка.
Каждый dbt run обрабатывает один или несколько последовательных интервалов. Backfill — это просто запуск с явным окном. Failure — повтор только не выполненных интервалов.
Минимальный пример microbatch
{{ config(
materialized='incremental',
incremental_strategy='microbatch',
event_time='order_created_at',
batch_size='day',
begin='2026-01-01'
) }}
SELECT
order_id,
customer_id,
amount,
order_created_at
FROM {{ source('jaffle_shop', 'raw_orders') }}
Разберём параметры:
incremental_strategy='microbatch'— стратегия.event_time='order_created_at'— колонка с timestamp события. dbt будет фильтровать по ней.batch_size='day'— размер интервала: hour, day, month, year.begin='2026-01-01'— самое раннее время, начиная с которого нужно обрабатывать. Защита от случайного backfill всей истории.
Обрати внимание: нет ручного {'{% if is_incremental() %}'}. dbt сам подставляет фильтр на event_time для каждого batch.
Как работает batch в microbatch
При dbt run без флагов dbt вычисляет текущий batch:
- Если today = 2026-05-19, batch_size = day -> batch = [2026-05-19 00:00:00, 2026-05-20 00:00:00).
- dbt применяет фильтр
WHERE order_created_at >= '2026-05-19 00:00:00' AND order_created_at < '2026-05-20 00:00:00'. - Существующие данные за этот день удаляются (или мерджатся, зависит от warehouse).
- Новые данные вставляются.
Для backfill используются флаги --event-time-start и --event-time-end:
# Backfill за неделю
dbt run --select fact_orders --event-time-start 2026-05-12 --event-time-end 2026-05-19
dbt создаст 7 batches по дням, обработает последовательно (или параллельно через concurrent_batches config). Каждый batch заменит данные за свой день.
Преимущества microbatch
1. Idempotent backfill. Запуск с тем же event-time-start/end дважды даст тот же результат. Не нужно бояться повторных запусков.
2. Параллельная обработка. На больших объёмах batches можно делать параллельно. Конфиг concurrent_batches: true включает это.
3. Failure recovery. Если dbt run упал на batch’е 2026-05-15, можно перезапустить с явным указанием — dbt не повторит уже выполненные.
4. Explicit время. Не нужно думать “что такое max(updated_at)” — окна явные.
5. Удобно для late-arriving data. Если события за вчера приходят сегодня — backfill вчерашнего дня корректно их учтёт.
Ограничения
1. Нужна event_time колонка. Каждая строка должна иметь timestamp. Если в источнике её нет — нельзя использовать microbatch.
2. Granularity ограничена. Только hour/day/month/year. Не minute, не custom.
3. Не делает upserts (по дизайну). Microbatch не имеет unique_key. Внутри batch он DELETE+INSERT всё. Это значит: если у тебя одно событие нужно обновить в существующем дне, всё равно перезалится весь день. Чтобы сделать upsert внутри batch — используй классический incremental с merge.
4. dbt-duckdb ограничение: unique_key НЕ поддерживается. Это критично на DuckDB: microbatch + unique_key даст config error.
В dbt-duckdb для microbatch unique_key не разрешён. Если ты добавишь unique_key=‘order_id’ к стратегии microbatch — получишь Compilation Error. На других warehouse (Snowflake/BigQuery) microbatch может работать с unique_key в более продвинутых режимах. На DuckDB используй классический incremental с merge, если нужны upsert’ы внутри окна.
Когда microbatch vs классический incremental
Microbatch — для случаев, где важна явная работа с временными окнами: backfill, restating, large-scale параллельно. Классический — для регулярного добавления свежих данных, особенно когда нужны upserts.
Microbatch: events, page views, transactions с timestamp, где история может пересчитываться.
Классический incremental: orders, users, dimensions с unique_key, где главное обновление существующих и добавление новых.
Параметры microbatch — расширенный список
{{ config(
materialized='incremental',
incremental_strategy='microbatch',
event_time='order_created_at',
batch_size='day',
begin='2026-01-01',
lookback=3, -- сколько batches смотреть назад при regular run
concurrent_batches=true -- параллельная обработка
) }}
lookback— при regular run dbt обработает не только сегодняшний batch, но и предыдущие N. Полезно для late-arriving data (события из вчера могут прийти сегодня).concurrent_batches— на больших backfill’ах позволяет параллельно обрабатывать несколько batches. На DuckDB single-writer per file, поэтому имеет лимит.
CLI флаги для microbatch
# Regular run — обработает текущий batch
dbt run --select fact_orders
# Backfill конкретного интервала
dbt run --select fact_orders --event-time-start 2026-05-01 --event-time-end 2026-05-19
# Только один день
dbt run --select fact_orders --event-time-start 2026-05-15 --event-time-end 2026-05-16
# Full refresh обходит microbatch — обрабатывает всё с begin до текущего
dbt run --select fact_orders --full-refresh
--event-time-start и --event-time-end — главные новые флаги в dbt 1.9.
Скомпилированный SQL для microbatch
Примерно так выглядит SQL одного batch’а (упрощённо):
-- DELETE прошлых данных за этот день
DELETE FROM target.fact_orders
WHERE order_created_at >= '2026-05-19 00:00:00'
AND order_created_at < '2026-05-20 00:00:00';
-- INSERT новых данных за этот день
INSERT INTO target.fact_orders
SELECT
order_id,
customer_id,
amount,
order_created_at
FROM source.raw_orders
WHERE order_created_at >= '2026-05-19 00:00:00'
AND order_created_at < '2026-05-20 00:00:00';
DELETE+INSERT внутри окна. Без unique_key — поэтому если внутри окна у тебя одна и та же запись пришла два раза, обе попадут в результат.
DuckDB-специфика для microbatch
- microbatch поддерживается в dbt-duckdb с версии 1.9+ — нужен свежий пакет.
- unique_key запрещён — это hard limitation адаптера. Конфиг error при попытке использовать.
- concurrent_batches работает в пределах одного process’а — DuckDB single writer per file, поэтому parallelism ограничен.
- DuckDB быстрый, batches маленькие — на локальных данных microbatch почти не даёт benefit’а. Главный сценарий — на больших облачных warehouse с миллиардами строк.
Команды для отладки microbatch
# Посмотреть, какие batches dbt планирует
dbt run --select fact_orders --event-time-start 2026-05-01 --event-time-end 2026-05-19 --dry-run
Output покажет список batches, которые будут выполнены.
# Включить debug-логи для понимания
dbt run --select fact_orders --debug
В логах увидишь подробности компиляции каждого batch’а — какие даты обрабатываются.
Попробуй сам (если есть DuckDB 1.4+ и dbt-core 1.9+)
Создай models/marts/fact_events_micro.sql:
{{ config(
materialized='incremental',
incremental_strategy='microbatch',
event_time='created_at',
batch_size='day',
begin='2024-01-01'
) }}
SELECT
order_id,
customer_id,
amount,
created_at
FROM {{ source('jaffle_shop', 'raw_orders') }}
Запусти:
dbt run --select fact_events_micro
При первом run обработает все batches от begin до сегодня. На небольшой raw это быстро.
Затем попробуй backfill только одного дня:
dbt run --select fact_events_micro --event-time-start 2024-06-15 --event-time-end 2024-06-16
Этот run обработает только данные за 2024-06-15. Старые данные за этот день удалятся и заменятся новыми.
Попробуй добавить unique_key=‘order_id’ в config — получишь ошибку, потому что dbt-duckdb это запрещает.
Что мы поняли
Microbatch — incremental-стратегия для time-based данных, появилась в dbt-core 1.9. Работает через event_time + batch_size, обрабатывает порциями по интервалам. Главные преимущества: idempotent backfill, late-arriving data, параллелизм. Главные ограничения: нужна event_time колонка, нет upserts (по дизайну), в dbt-duckdb unique_key запрещён. На junior-уровне — знать концепт и ограничения. На middle/senior — глубже разберём backfill, параллелизм, восстановление.
На этом мы закрыли модуль про incremental. В следующем модуле — тесты: четыре встроенных generic теста (not_null, unique, accepted_values, relationships).
Microbatch: концепт и зачем он появился — углублённый разбор Batch-обработка: окна, расписание, идемпотентность