Короткий ответ
Идемпотентность означает, что безопасный повтор батча не меняет итог сверх результата первого успешного выполнения и не создаёт дубликаты.
Как это работает подробнее
Простой append нарушает это свойство при ретрае. Идемпотентная загрузка связывает каждую строку с устойчивым ключом и либо обновляет существующую запись, либо полностью заменяет ограниченный обрабатываемый срез.
- UPSERT. Подходит для сущностей с надёжным уникальным ключом.
- Delete and insert. Удобен для атомарной перезаписи партиции или диапазона дат.
- Checkpoint. Продвигается только после успешной фиксации всего батча.
Пример кода
upsert_orders.sql
INSERT INTO fact_orders (order_id, customer_id, amount, load_date)
SELECT order_id, customer_id, amount, CURRENT_DATE
FROM staging_orders
ON CONFLICT (order_id) DO UPDATE
SET customer_id = EXCLUDED.customer_id,
amount = EXCLUDED.amount,
load_date = EXCLUDED.load_date;Что использовать на практике
- Запускайте один и тот же тестовый батч дважды и сравнивайте количество строк, контрольные суммы и значения.
- Выполняйте замену среза и обновление checkpoint в одной транзакции или эквивалентной атомарной операции.
Подводные камни
- Изменчивый ключ. Если бизнес-ключ нестабилен, UPSERT создаст новую строку вместо обновления.
- Поздние данные. Слишком узкое инкрементальное окно пропустит запоздавшие изменения.