Инкрементальная загрузка
Урок объясняет, как грузить только новые данные, а не всю таблицу каждый раз.
Инкрементальная загрузка — извлечение из источника только данных, изменившихся с прошлого запуска, по «водяному знаку» (watermark).
Зачем не грузить всё заново
Полная перезаливка (full load) проста, но не масштабируется: когда в источнике сто миллионов строк, читать их целиком каждый час невозможно. Инкрементальная загрузка забирает только новое — например, заказы с created_at больше последней обработанной даты. Это и есть водяной знак: метка «докуда мы дочитали».
full load: каждый раз тащим ВСЕ 100 млн строк (дорого)
incremental: watermark = 2026-06-21 10:00
тащим только WHERE created_at > watermark (дёшево)Инкрементальная загрузка превращает время работы конвейера из «зависит от общего размера данных» в «зависит от объёма новых данных». Это качественный скачок: таблица растёт годами, а ежечасный запуск остаётся быстрым, потому что обрабатывает лишь свежую порцию. Именно так устроены практически все промышленные конвейеры на больших источниках — полная перезаливка остаётся только для маленьких справочников.
Как работает под капотом
Источник на SQL: выбираем только записи новее водяного знака.
CREATE TABLE source_orders (id INTEGER PRIMARY KEY, created_at TEXT, amount INTEGER);
INSERT INTO source_orders VALUES
(1,'2026-06-20',300), (2,'2026-06-21',500), (3,'2026-06-22',700);
-- watermark из прошлого запуска: 2026-06-21
SELECT id, created_at, amount
FROM source_orders
WHERE created_at > '2026-06-21'
ORDER BY created_at;Логика обновления водяного знака на чистом Python: грузим новое и сдвигаем метку на максимум обработанного.
source = [
{"id": 1, "ts": "2026-06-20"},
{"id": 2, "ts": "2026-06-21"},
{"id": 3, "ts": "2026-06-22"},
]
watermark = "2026-06-21"
new_rows = [r for r in source if r["ts"] > watermark]
print("Новых записей:", len(new_rows))
if new_rows:
watermark = max(r["ts"] for r in new_rows)
print("Новый watermark:", watermark)Вывод:
Новых записей: 1 Новый watermark: 2026-06-22
Водяной знак — это маленькое состояние, которое конвейер несёт от запуска к запуску. Его обычно хранят в таблице-метаданных, в переменной Airflow или прямо в имени последней загруженной партиции. Главное правило — обновлять watermark только после того, как новые данные успешно загружены в приёмник. Если сдвинуть метку раньше и загрузка упадёт, эти записи будут потеряны навсегда: следующий запуск решит, что они уже обработаны.
Полная и инкрементальная — когда что
| Full load | Incremental |
| маленькие справочники | большие журналы событий |
| просто, всегда консистентно | дёшево, но сложнее |
Частые ошибки
- Брать
>=вместо>по водяному знаку. Граничные записи обработаются дважды; либо строго>, либо upsert для защиты от дублей. - Опоздавшие записи. Если событие пришло в источник с задержкой и его дата меньше watermark, инкремент его пропустит — нужен запас или окно перезахвата.
- Хранить watermark в памяти задачи. Его место — во внешнем состоянии (таблица, переменная Airflow), иначе он теряется между запусками.
Итог
- Инкрементальная загрузка тащит только новые данные по водяному знаку.
- Это масштабируется на большие источники в отличие от полной перезаливки.
- Watermark хранят во внешнем состоянии, а захват делают идемпотентным.