Обработка больших объёмов данных в SQL требует особого подхода для предотвращения переполнения памяти, блокировок и обеспечения стабильной производительности. Один из главных приёмов — разбивка операций на батчи: входные данные обрабатываются небольшими порциями, что снижает нагрузку на сервер и позволяет лучше контролировать транзакции и откаты при ошибках.
Ключевые аспекты:
ROWCOUNT или LIMIT / TOP)COMMIT, чтобы разгрузить транзакционный логПример (SQL Server):
DECLARE @BatchSize INT = 1000; WHILE 1 = 1 BEGIN BEGIN TRANSACTION; DELETE TOP(@BatchSize) FROM BigLogTable WHERE CreatedDate < '2021-01-01'; IF @@ROWCOUNT = 0 BREAK; COMMIT TRANSACTION; END
Как удалить 100 миллионов записей из большой таблицы с минимальным влиянием на производительность?
Некорректный ответ: "Сделать один большой DELETE".
Корректный ответ: Удалять порциями (батчами) с контролем размера батча, делать COMMIT после каждого блока, при необходимости снижать нагрузку на диск и блокировки с помощью пауз (WAITFOR DELAY или аналог).
Пример (PostgreSQL):
DO $$ BEGIN LOOP DELETE FROM big_table WHERE created_at < NOW() - interval '1 year' LIMIT 10000; EXIT WHEN NOT FOUND; COMMIT; END LOOP; END$$;
История
Проект: Высоконагруженный банковский сервис. Ошибка: Разработчик запустил удаление устаревших логов одним большим запросом на 80 млн строк. Итог — лог транзакций вырос до терабайтов, выбило все доступное дисковое пространство, сервис "упал".
История
Проект: Интернет-магазин с системой складского учета. Ошибка: При массовой вставке не был ограничен размер транзакции. В процессе импорта массивных батчей записи пошли с ошибками, всю предыдущую работу пришлось откатывать и повторять, заняло часы вместо минут.
История
Проект: Ритейлер, отчетная БД детализации заказов. Ошибка: Использовали батчи, но забыли про COMMIT между итерациями — транзакционный лог рос экспоненциально, сервер начал "тормозить", а затем потребовалась экстренная очистка логов штатными средствами.