Прямой ответ
Выбор способа обновления определяется требованием к корректности и объёмом данных. Полное обновление проще и корректнее, инкрементальное дешевле при большом объёме.
| Критерий | Полное обновление | Инкрементальное |
|---|---|---|
| Корректность результата | Полная | Зависит от определения границы |
| Обработка удалений | Автоматическая | Требует отдельного механизма |
| Объём переноса | Весь набор | Изменившаяся часть |
| Требование к источнику | Возможность полного чтения | Отметка изменения либо журнал |
| Влияние ошибки | Исправляется следующим запуском | Накопление расхождения |
-- Полное обновление: замена содержимого
BEGIN;
TRUNCATE mart.orders_snapshot;
INSERT INTO mart.orders_snapshot SELECT * FROM dwh.orders;
COMMIT;
-- Инкрементальное обновление: только изменённая часть
INSERT INTO dwh.orders AS d
SELECT * FROM src.orders WHERE updated_at > :watermark
ON CONFLICT (order_id) DO UPDATE
SET amount_minor = EXCLUDED.amount_minor,
updated_at = EXCLUDED.updated_at;
Полное обновление переносит весь набор, поэтому удалённые в источнике строки исчезают из результата автоматически. Инкрементальное обновление переносит изменившуюся часть, поэтому удаление строки в источнике не обнаруживается; о механизме — в статье про инкрементальную загрузку.
Корректность результата и накопление расхождения
Главное различие способов — поведение при ошибке.
Полное обновление исправляет ошибку следующим запуском. Результат строится целиком из текущего состояния источника, поэтому расхождение, возникшее в предыдущем запуске, исчезает.
Инкрементальное обновление накапливает расхождение. Ошибка в одном интервале остаётся в данных до обнаружения и исправления. Пропущенный интервал требует отдельного пересчёта.
Практическое следствие: при отсутствии контроля согласованности инкрементальная загрузка даёт расхождение, которое растёт со временем.
Отдельный аспект — задержка данных. Полное обновление выполняется дольше, поэтому периодичность запуска ниже и данные отстают сильнее. Инкрементальное обновление выполняется быстрее и запускается чаще.
Стоимость полного обновления растёт пропорционально объёму данных, поэтому при большом наборе время загрузки может превысить интервал между запусками. Оценка времени по наблюдаемым значениям выполняется по методике из статьи про capacity planning.
Три признака в пользу полного обновления.
Малый объём данных. Время загрузки сопоставимо с инкрементальным, поэтому выигрыш в простоте перевешивает.
Отсутствие отметки изменения. Источник не предоставляет способ определить изменившуюся часть, поэтому инкрементальная загрузка требует сравнения наборов.
Частые удаления. Обнаружение удалений при инкрементальной загрузке требует отдельного механизма, сопоставимого по сложности с полным обновлением.
Влияние на нагрузку и эксплуатационную сложность
Выбор способа определяет не только время загрузки, но и нагрузку на систему.
Объём записи. Полное обновление записывает весь набор при каждом запуске, что увеличивает объём записи и нагрузку на очистку. Инкрементальное обновление записывает изменившуюся часть.
Блокировки. Замена содержимого таблицы требует блокировки на время операции. При полном обновлении читатель либо видит старое содержимое, либо ждёт завершения.
Идемпотентность. Полное обновление идемпотентно по определению: повторный запуск даёт тот же результат. Инкрементальное обновление требует явного обеспечения идемпотентности; о механизме — в статье про повторы загрузки.
Сопровождение. Инкрементальная загрузка требует хранения границы, контроля пропущенных интервалов и периодической сверки. Полное обновление не требует состояния между запусками.
Практическое следствие: инкрементальная загрузка сокращает объём переноса, но добавляет состояние, которое требуется сопровождать.
Распространённая схема сочетает оба способа: инкрементальная загрузка выполняется по расписанию, полное обновление — периодически для исправления накопленных расхождений.
Отдельный аспект — атомарность. Полное обновление выполняется в транзакции либо через замену таблицы, чтобы читатель не видел частично обновлённые данные.
Сочетание способов обновления
Распространённая схема использует оба способа: инкрементальная загрузка по расписанию и периодическое полное обновление.
Инкрементальная часть обеспечивает малую задержку данных при умеренной стоимости, поскольку переносится изменившаяся часть. Запускается по короткому расписанию.
Полная часть исправляет расхождения, накопленные инкрементальной загрузкой, и обрабатывает удаления. Запускается реже, поскольку требует времени и ресурсов.
Практическое следствие: периодичность полного обновления определяется допустимым временем существования расхождения. Если расхождение обнаруживается сверкой раньше, полное обновление выполняется по факту обнаружения.
Отдельный аспект — согласование расписаний. Полное обновление не выполняется одновременно с инкрементальным, поскольку оба пишут в одну таблицу и конкурируют за блокировки.
Практика: выбор и сопровождение способа обновления
1. Оцените объём данных и время загрузки. При малом объёме полное обновление проще, при большом — инкрементальное дешевле.
2. Уточните наличие отметки изменения. Без отметки и журнала инкрементальная загрузка требует сравнения наборов.
3. Учтите частоту удалений. Частые удаления делают инкрементальную загрузку сопоставимой по сложности с полным обновлением.
4. Обеспечьте атомарность обновления. Читатель не должен видеть частично обновлённые данные.
5. Планируйте периодическое полное обновление. Оно исправляет расхождения, накопленные инкрементальной загрузкой.
6. Контролируйте согласованность с источником. Периодическая сверка агрегатов выявляет расхождение до обращения пользователя.
7. Учитывайте нагрузку на очистку. Объём записи при полном обновлении увеличивает нагрузку на обслуживание базы.
Рекомендации:
- Различайте объём переноса и объём записи. Инкрементальная загрузка сокращает перенос, но повторная обработка строк увеличивает запись.
- Храните границу изменения надёжно. Потеря границы делает невозможным определение следующего интервала.
- Не полагайтесь только на инкрементальную загрузку. Периодическое полное обновление ограничивает накопление расхождения.
- Сверяйте результат с источником. Сравнение числа строк и агрегатов выявляет пропуск данных между интервалами.
- Фиксируйте задержку данных. Потребитель должен знать, на какой момент актуальны данные при каждом способе обновления.
Практический сценарий: инкрементальная загрузка накопила расхождение
Контекст: отчёт расходился с учётной системой на величину, которая росла от месяца к месяцу.
- Диагностика. Загрузка выполнялась по отметке обновления без запаса по границе. Интервалы, пропущенные из-за длительных транзакций источника, не пересчитывались, поэтому расхождение накапливалось.
- Причина. Инкрементальная загрузка не имеет механизма исправления ошибки: пропущенный интервал остаётся незаполненным до явного пересчёта. Периодическое полное обновление не выполнялось, поэтому расхождение не устранялось.
- Действия. (а) Добавили запас по границе, перекрывающий длительность транзакций источника; (б) ввели ежемесячное полное обновление для исправления накопленных расхождений; (в) настроили ежедневную сверку агрегатов с источником; (г) выполнили полный пересчёт за период расхождения; (д) добавили журнал интервалов загрузки с числом перенесённых строк для обнаружения пропусков.
- Результат. Расхождение устраняется в течение суток сверкой и в течение месяца полным обновлением.
Вывод: инкрементальная загрузка без контроля согласованности накапливает расхождение, поскольку ошибка в интервале не исправляется следующим запуском. Периодическое полное обновление и регулярная сверка ограничивают накопление.
FAQ
Какой способ корректнее? Полное обновление, поскольку результат строится целиком из текущего состояния источника и ошибка исправляется следующим запуском.
Можно ли сочетать оба способа? Да, распространённая схема: инкрементальная загрузка по расписанию и периодическое полное обновление для исправления расхождений.
Как полное обновление обрабатывает удаления? Автоматически, поскольку содержимое заменяется целиком. Инкрементальная загрузка требует отдельного механизма обнаружения удалений.
Что дешевле при большом объёме данных? Инкрементальная загрузка, поскольку переносится изменившаяся часть. Полное обновление переносит весь набор при каждом запуске.
Источники: PostgreSQL TRUNCATE, MERGE, routine vacuuming — ссылки в шапке.