Архивация данных — одна из важнейших задач для высоконагружённых OLTP-систем с большими таблицами. Исторически первые попытки реализовать это были крайне просты: данные удалялись или копировалиcь в отдельные таблицы вручную через скрипты либо приложения. Позже появились более системные подходы, учитывающие транзакционную целостность и минимальное влияние на основную работу базы.
Проблема здесь заключается не только в физическом переносе информации, но и в поддержании согласованности, минимизации блокировок и обеспечении высокой производительности. Ошибки при архивации могут привести к потере данных, блокировке пользователей или существенному росту нагрузки.
Решением является использование батч-операций с транзакционным контролем, а также формирование специальных архивных таблиц с идентичной структурой, либо автоматизация через планировщик задач и процедуры.
Пример кода:
-- Переносим по 5000 записей старше года в архивную таблицу INSERT INTO archive_orders SELECT * FROM orders WHERE order_date < DATEADD(year, -1, GETDATE()) AND id IN (SELECT TOP 5000 id FROM orders WHERE order_date < DATEADD(year, -1, GETDATE()) ORDER BY id); DELETE FROM orders WHERE id IN (SELECT TOP 5000 id FROM orders WHERE order_date < DATEADD(year, -1, GETDATE()) ORDER BY id);
Ключевые особенности:
Какой риск есть при массовом DELETE старых записей и как этого избежать?
Массовый DELETE может привести к эскалации блокировок и торможению работы всей базы. Этого можно избежать, производя удаление малыми порциями внутри цикла или с помощью LIMIT/TOP, если поддерживается СУБД.
WHILE 1=1 BEGIN DELETE TOP (1000) FROM orders WHERE order_date < '2023-01-01'; IF @@ROWCOUNT = 0 BREAK; END
Можно ли использовать TRUNCATE для удаления архивируемых данных?
TRUNCATE удаляет все строки в таблице и не подходит для условной очистки определённых строк. Он не вызывает триггеры, не поддерживает WHERE и используется только для полной очистки, а не выборочной архивации.
Как гарантировать, что перенос прошёл корректно, если удаление и вставка делаются в разных транзакциях?
Лучше делать перенос строки в одной транзакции: сначала копируем в архив, затем удаляем из основной. Иначе можно получить несогласованность в случае сбоя между операциями.
BEGIN TRANSACTION INSERT INTO archive_orders SELECT * FROM orders WHERE ... DELETE FROM orders WHERE ... COMMIT
Инженер запускает скрипт на миллион записей DELETE FROM logs WHERE event_date < '2022-01-01' во время рабочего дня.
Плюсы:
Минусы:
Спланирован перенос по 5000 строк через хранимую процедуру и задание по расписанию ночью, с логированием успеха каждой порции.
Плюсы:
Минусы: