Массовое удаление десятков миллионов строк — одна из типичных и самых опасных операций, особенно в высоконагружённых базах. Исторически многие просто писали DELETE FROM, что приводило к блокировкам таблицы и переполнению лога транзакций. Основная проблема: транзакция становится слишком большой, обслуживающие процессы тормозят, а последствия отката могут быть труднопредсказуемыми.
Решение — реализовать удаление "пакетно" (batch), обрабатывая небольшое количество строк в цикле с короткими транзакциями, чтобы минимизировать блокировки и влияние на систему:
Пример кода (SQL Server):
WHILE 1=1 BEGIN DELETE TOP (10000) FROM YourHugeTable WHERE CreatedAt < DATEADD(year,-2,GETDATE()); IF @@ROWCOUNT = 0 BREAK; WAITFOR DELAY '00:00:01'; -- небольшая пауза для снижения нагрузки END
Ключевые особенности:
Если сделать TRUNCATE вместо DELETE, всегда ли это быстрее и безопаснее?
Нет. TRUNCATE гораздо быстрее, но :
В массовом DELETE важно ли использовать индексы по полю фильтра?
Да, наличие подходящего индекса по столбцу фильтра (например, CreatedAt) ускоряет поиск удаляемых строк и снижает нагрузку на таблицу. Без индекса запрос затронет всю таблицу, даже если в каждой порции удаляется небольшое количество строк.
CREATE INDEX idx_createdat ON YourHugeTable(CreatedAt);
Что будет, если выполнять несколько потоков массового DELETE одновременно?
Это приведет к конкуренции за блокировки: возникнут эскалации блокировок, рост времени ожидания и вероятность deadlock. Массовое удаление из одной таблицы должно вестись одним процессом, либо с очень аккуратно продуманным делением диапазонов.
DBA решил очистить таблицу на 60 млн строк однократным запросом DELETE FROM Log WHERE dt < '2021-01-01'. Сервер почти "повис", остальные процессы начали ждать выполнения, жестко вырос файл лога, восстановление стало длинным.
Плюсы:
Минусы:
Удаление делили на пакеты по 10 000 строк, процесс контролируется, после каждой порции пауза. Сервер работаeт стабильно, остальные задачи выполняются, админ мониторит прогресс.
Плюсы:
Минусы: