При обслуживании крупных информационных баз 1С разработчики и администраторы периодически сталкиваются с необходимостью массовой очистки устаревших данных. Если требуется удалить десятки миллионов документов или записей регистров с отбором по дате, стандартные средства платформы (такие как метод УдалитьОбъекты() или фоновое удаление в цикле) оказываются неприменимы из-за высокой длительности выполнения. Попытка выполнить простую команду DELETE напрямую в MS SQL Server также может занять долгие часы, поскольку СУБД вынуждена на каждую удаляемую строку перестраивать все существующие индексы таблицы и заполнять журнал транзакций.
Рассмотрим, как оптимизировать процесс массового удаления данных средствами MS SQL Server и уложиться в минимальное технологическое окно простоя базы данных.
Выясним причину, почему обычный запрос на удаление выполняется крайне медленно. При выполнении инструкции DELETE над крупной таблицей СУБД выполняет следующие ресурсоемкие операции:
DELETE относится к полностью журналируемым операциям. Каждая удаляемая строка фиксируется в транзакционном логе.READ_COMMITTED_SNAPSHOT (RCSI), из-за чего удаляемые версии строк копируются в системную базу данных tempdb.Проанализируем наиболее быстрый практический подход, позволяющий сократить время удаления десятков миллионов записей с нескольких часов до нескольких минут.
Суть метода заключается в том, чтобы отключить все некластерные индексы перед выполнением удаления, выполнить удаление одной командой с хинтом блокировки таблицы, а затем выполнить полное пересоздание (rebuild) индексов.
Разберем данный процесс по шагам:
Для отключения всех индексов на целевой таблице выполним T-SQL команду DISABLE. В отключенном состоянии индексы не обновляются при операциях изменения данных:
ALTER INDEX ALL ON _Document123 DISABLE;
При этом кластерный индекс (если удаление происходит не по нему) можно оставить активным или временно оставить только индекс по полю даты для ускорения поиска отбираемых строк.
Для предотвращения эскалации блокировок и ускорения работы укажем хинт WITH (TABLOCKX), который блокирует всю таблицу целиком на время выполнения транзакции:
DELETE FROM _Document123 WITH (TABLOCKX)
WHERE _DateDev < '2020-01-01';
Благодаря отключенным индексам СУБД производит удаление строк напрямую из первичной структуры данных, не отвлекаясь на поддержание порядка в индексах.
После завершения удаления необходимо восстановить работоспособность индексов. Включение индекса в MS SQL Server выполняется путем его полной пересборки:
ALTER INDEX ALL ON _Document123 REBUILD;
Практический результат: На тестовых замерах удаление 30 миллионов документов из таблицы размером более 15 ГБ без индексов занимает около 16 минут, а последующее пересоздание всех индексов — около 28 минут. Итоговое время выполнения задачи составляет менее 45 минут, что легко вписывается в технологическое окно простоя.
Если полностью остановить работу пользователей невозможно или размер журнала транзакций строго ограничен, рассмотрим вариант удаления данных квантами (порциями) в цикле. Данный метод позволяет контролировать размер транзакций и предотвратить бесконечный рост журнала логов.
Посмотрим на пример T-SQL скрипта для пакетного удаления:
DECLARE @RowsDeleted INT = 1;
WHILE @RowsDeleted > 0
BEGIN
DELETE TOP (100000)
FROM _Document123 WITH (TABLOCKX)
WHERE _DateDev < '2020-01-01';
SET @RowsDeleted = @@ROWCOUNT;
END
При использовании этого метода размер порции (например, 50 000 – 100 000 записей) подбирается эмпирическим путем. Главное преимущество пакетного удаления — возможность визуально отслеживать прогресс выполнения и не блокировать всю базу данных на длительное время.
Разберем дополнительные системные настройки MS SQL Server, которые помогут максимально ускорить процесс очистки крупных таблиц:
SIMPLE (Простая). Это предотвратит переполнение файла журнала транзакций (.ldf). После окончания работ модель восстановления переводится обратно в FULL с обязательным созданием резервной копии.tempdb:
ALTER DATABASE [ИмяБазы] SET READ_COMMITTED_SNAPSHOT OFF;
После завершения всех процедур режим следует включить обратно:
ALTER DATABASE [ИмяБазы] SET READ_COMMITTED_SNAPSHOT ON;
tempdb имеют достаточное свободное место. Автоматический прирост файлов (Autogrowth) во время выполнения операции DELETE вызывает паузы в работе СУБД.ПолучитьСтруктуруХраненияБазыДанных(). Это позволит автоматически сформировать T-SQL скрипты для отключения и включения нужных индексов конкретного документа или регистра.Таким образом, сочетание отключения некластерных индексов перед удалением, применение прямых T-SQL инструкций с блокировкой таблицы TABLOCKX и последующий перерасчет индексов представляют собой наиболее эффективный и проверенный способ очистки завышенных объемов данных в 1С.