Конфигурация microbatch: event_time, batch_size, begin, lookback
В прошлом уроке мы видели microbatch на высоком уровне. Сегодня — детально разберём все четыре главных параметра: event_time, batch_size, begin, lookback. Правильная настройка этих параметров определяет, будет ли microbatch работать быстро и корректно, или превратится в источник багов.
event_time — главный параметр
event_time — это колонка модели, по которой microbatch определяет границы батчей. Это timestamp / date колонка в SELECT-statement модели.
{{ config(
materialized='incremental',
incremental_strategy='microbatch',
event_time='event_timestamp',
batch_size='day',
begin='2024-01-01'
) }}
select
event_id,
user_id,
event_timestamp, -- эта колонка указана в event_time
event_type
from {{ ref('stg_events') }}
Правила выбора event_time:
- Колонка ДОЛЖНА быть в SELECT-statement — dbt должен видеть её в output модели для правильного DELETE/INSERT.
- Timestamp/date type — TIMESTAMP, DATE, DATETIME. Strings не работают.
- UTC рекомендуется — критично для batch boundaries (разберём в уроке 4).
- Immutable — event_time не должен меняться после insertion. Это timestamp события, не loaded_at.
- Природный partitioning column — то, по чему данные естественно группируются по времени.
Типичные правильные event_time:
event_timestamp— для event tables.created_at— для order tables (когда order создан).transaction_date— для finance tables.measurement_at— для IoT telemetry.
Типичные неправильные event_time:
loaded_at— меняется при retry источника, ломает idempotency.updated_at— может меняться задним числом, ломает batch boundaries.last_seen_at— постоянно обновляется, microbatch будет переписывать сам себя.
batch_size — размер батча
batch_size определяет, как большой каждый batch. Опции: hour, day, month, year.
Меньше batch_size — больше batches, лучше parallelism и retry granularity. Больше batch_size — меньше overhead, проще backfill.
Эмпирические правила:
hour— когда event-volume > 100M/день. Иначе overhead.day— production default. 90% случаев.month— для monthly aggregates, MRR snapshots, financial closing.year— редко. Только historical snapshots или yearly compliance reports.
begin — начальная дата
begin — первый batch для backfill. На самом первом dbt run microbatch создаёт batches от begin до текущего момента.
config:
begin: '2024-01-01'
Несколько важных моментов:
beginобязателен — без него microbatch не знает, откуда начинать.beginв форматеYYYY-MM-DD— date string в UTC.beginне меняйте после первого run — иначе microbatch не понимает, где история. Если нужно переcчитать с более раннего begin —dbt run --full-refreshс новым begin.beginобычно ставят 1-2 года назад — purpose’a включить весь исторический скоп для backfill.
Пример: ваши events начались с 2024-01-01, поставьте begin: '2024-01-01'. На первом run microbatch создаст ~730 batches (365 × 2 года) — каждый по дню. Это дорогой первый run, но дальше каждый dbt run обработает только последние 1-2 batches.
lookback — переcчёт предыдущих batches
lookback — сколько предыдущих batches переcчитывать на каждом run (default 1).
config:
lookback: 3 # пересчитываем последние 3 batches
Зачем нужен lookback? Потому что late-arriving events могут пройти в прошлые batches. Например:
- Сегодня 2026-05-19, 14:00 UTC.
- Микро batch granularity =
day. - Последний batch — 2026-05-19.
- Event с
event_timestamp = '2026-05-17 10:00'пришёл в источник сейчас (late-arrival). - Если lookback=1 — microbatch переcчитывает только 2026-05-19, late event попадёт в этот batch (но event_timestamp 2026-05-17, microbatch batch это 2026-05-19 — событие не пройдёт фильтр).
- Если lookback=3 — microbatch переcчитывает 2026-05-17, 18, 19, late event попадёт в свой batch (2026-05-17).
Без lookback не меньше 1 microbatch теряет late-arrivals в той же мере, что обычный incremental без lookback.
Дефолт lookback=1 означает «переcчитываем только текущий batch + 1 предыдущий». На production это часто недостаточно. Production-обычай — lookback=3 для daily batches и lookback=12-24 для hourly batches.
Полный пример с правильными параметрами
{{ config(
materialized='incremental',
incremental_strategy='microbatch',
event_time='event_timestamp',
batch_size='day',
begin='2024-01-01',
lookback=3,
full_refresh=false
) }}
select
event_id,
user_id,
event_type,
event_timestamp,
event_properties,
case
when event_type = 'purchase' then properties:amount::float
else null
end as purchase_amount
from {{ ref('stg_events') }}
Параметры:
event_time='event_timestamp'— UTC timestamp событий.batch_size='day'— батч = день.begin='2024-01-01'— backfill с начала 2024.lookback=3— переcчитывать последние 3 дня для catch’а late events.full_refresh=false— запрещает--full-refreshдля этой модели (защита от случайного полного пересчёта).
—full-refresh paths
По умолчанию dbt run --full-refresh работает на microbatch так:
- DROP target table.
- CREATE target.
- Запустить batches от
beginдоnowпоследовательно.
Это эквивалентно полному backfill из begin’а до сегодня. На таблице с 2 годами данных это пересчёт 730 batches — может занять часы.
full_refresh=false в config запрещает --full-refresh для модели. Если кто-то запустит dbt run --full-refresh --select my_model, dbt просто проигнорирует флаг для этой модели. Это защита от случайного пересчёта.
Этот параметр — production-must для microbatch моделей с большим volume. Без него один невнимательный --full-refresh может стоить часы compute и десятки долларов.
—event-time-start / —event-time-end
Главное преимущество microbatch — selective backfill через CLI флаги:
# Пересчитать только апрель 2026:
dbt run --select my_microbatch_model \
--event-time-start='2026-04-01' \
--event-time-end='2026-05-01'
dbt запустит batches только для дат внутри окна. Это surgical backfill: не пересчитываем все два года, только нужный период.
Use cases:
- Исправили баг в логике (
case when event_type = 'purchase' ...), нужно пересчитать апрель 2026 —--event-time-start='2026-04-01' --event-time-end='2026-05-01'. - Source задним числом загрузил историю — пересчитать только этот период.
- Тестируем новую модель — пересчитать неделю для проверки.
Без --event-time-end окно открытое — microbatch пересчитывает с --event-time-start до now. Это часто не то, что хотите. Всегда указывайте оба флага явно.
Концептуальный пример: расчёт batches
Допустим:
begin = '2024-01-01'batch_size = 'day'lookback = 3- Сегодня = 2026-05-19, 14:00 UTC
- Last run was 2026-05-19, 10:00 UTC (4 часа назад)
Что произойдёт на новый dbt run:
- dbt находит max(event_time) в target — допустим 2026-05-19 09:00.
- dbt вычисляет последний полностью обработанный batch — 2026-05-18 (так как 2026-05-19 ещё не закончился по
dayboundary). - lookback=3 значит обработать batches: 2026-05-16, 17, 18.
- Плюс новый batch — 2026-05-19 (текущий day, ещё открытый).
- dbt запускает 4 batches: 16, 17, 18, 19.
Каждый batch — это DELETE+INSERT для своего дня. Если на этот run приходят late events с timestamp 2026-05-15 — они НЕ попадут в target (вне lookback). Если хотите ловить такие — увеличьте lookback до 5+.
DuckDB-специфика
TIMESTAMP, TIMESTAMPTZ и часовые пояса в SQL- DuckDB поддерживает все four parameters microbatch.
event_timeдолжен быть TIMESTAMP / DATE — DuckDB strict про типы.beginaccepts string in ‘YYYY-MM-DD’ format.- Single-writer на DuckDB local — concurrent batches могут lock’аться. На MotherDuck — OK.
Production gotchas
1. event_time = loaded_at
Самая частая ошибка. loaded_at меняется при retry источника, microbatch пытается переписать batches с разными loaded_at, и target становится non-deterministic. event_time всегда должен быть immutable timestamp события, не загрузки.
2. begin изменили после первого run
Если на первом run был begin='2024-01-01', потом изменили на begin='2023-01-01' — microbatch не пересчитает 2023 автоматически. Нужен dbt run --full-refresh (или --event-time-start='2023-01-01' --event-time-end='2024-01-01' для surgical).
3. lookback=1 при late-arriving data
Дефолт 1. На production с любыми Fivetran/Airbyte задержками теряете late-arrivals. Поставьте lookback=3 для daily, 12+ для hourly.
4. batch_size=hour на маленькой таблице
Если данных мало (100K-1M строк/день), batch_size=‘hour’ создаёт 24 крошечных batch’а. Overhead на batch (DELETE empty, INSERT 0 rows) суммарно больше выигрыша. Используйте day или month.
5. full_refresh=true (default) на critical models
Без full_refresh=false один невнимательный —full-refresh может перезагрузить 2 года данных. Защитите критичные модели.
6. event_time в локальном timezone
UTC обязательно. Если event_timestamp в локальном timezone и переходит через midnight в локальной зоне, microbatch видит несколько days вместо одного. Batch boundaries ломаются.
Попробуй сам
В своём проекте:
- Возьмите event-таблицу. Проверьте, что есть UTC timestamp колонка.
- Создайте microbatch-модель с правильными параметрами. Поставьте
lookback=3. - Запустите
dbt run --select my_model. Посмотрите в логи — сколько batches запустилось? Что в каждом? - Поэкспериментируйте с
--event-time-start/--event-time-endдля backfill узкого окна. - Добавьте
full_refresh=falseи попробуйтеdbt run --full-refresh --select my_model— увидите, что не пересчитывается.