Периодически каждый разработчик и администратор баз данных 1С сталкивается с необходимостью удаления колоссальных объемов информации. Это могут быть задачи свертки базы данных перед переходом на новую конфигурацию, разделение учета по организациям с выгрузкой в отдельные базы или просто плановая очистка устаревших и неактуальных сведений. Когда речь заходит об удалении сотен тысяч или миллионов элементов (например, справочника номенклатуры вместе с подчиненными единицами измерения, штрихкодами, ценами и регистрами сведений), стандартные механизмы платформы начинают работать неприемлемо медленно. Штатная обработка «Удаление помеченных объектов» в таких сценариях может выполняться сутками, парализуя работу пользователей.
В этой статье мы подробно разберем, почему стандартное удаление происходит так медленно, проанализируем физику процесса на уровне СУБД и рассмотрим эффективные практические методы оптимизации, которые позволят сократить время удаления миллионов объектов с нескольких суток до нескольких часов.
Прежде чем переходить к оптимизации, выясним первопричину медленной работы платформы при удалении объектов. Проанализируем, что происходит «под капотом» системы, когда мы вызываем стандартное удаление:
DELETE.Теперь, понимая слабые места стандартного механизма, разберем по шагам наиболее эффективные способы ускорения этого процесса.
Самая распространенная ошибка начинающих разработчиков — попытка удаления объектов напрямую из выборки запроса или использование пообъектного удаления без явного управления транзакциями. Посмотрим на классический неоптимальный код:
// НЕПРАВИЛЬНО: Медленное удаление из выборки
Выборка = Справочники.ЕдиницыИзмерения.Выбрать();
Пока Выборка.Следующий() Цикл
Выборка.Ссылка.ПолучитьОбъект().Удалить();
КонецЦикла;
Этот код будет работать крайне медленно, так как при удалении объекта выборка может «сбиваться», а СУБД будет открывать и закрывать транзакцию для каждого отдельного элемента. Чтобы ускорить процесс в десятки раз, мы должны применить два важнейших правила: предварительное получение массива ссылок и группировку операций в транзакции.
Рассмотрим правильный шаблон реализации пакетного программного удаления:
// ПРАВИЛЬНО: Пакетное удаление в транзакциях
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения";
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
МассивСсылок = ТаблицаДанных.ВыгрузитьКолонку("Ссылка");
ВсегоОбъектов = МассивСсылок.Количество();
РазмерПорции = 1000; // Оптимальный размер порции для простых справочников
Индекс = 0;
Пока Индекс < ВсегоОбъектов Цикл
НачатьТранзакцию();
Попытка
Для К = 1 По РазмерПорции Цикл
ТекущийИндекс = Индекс + К - 1;
Если ТекущийИндекс >= ВсегоОбъектов Тогда
Прервать;
КонецЕсли;
СсылкаНаОбъект = МассивСсылок[ТекущийИндекс];
// Получаем объект и удаляем его непосредственно без проверок
Объект = СсылкаНаОбъект.ПолучитьОбъект();
Если Объект <> Неопределено Тогда
Объект.ОбменДанными.Загрузка = Истина; // Отключаем обработчики событий
Объект.Удалить();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписатьЛогОшибки(ОписаниеОшибки());
КонецПопытки;
Индекс = Индекс + РазмерПорции;
// Выводим состояние не на каждой итерации, а порционно!
Если Индекс % 10000 = 0 Тогда
Состояние("Удалено объектов: " + Индекс + " из " + ВсегоОбъектов);
КонецЕсли;
КонецЦикла;
Разберем, почему этот код работает в разы быстрее:
ОбменДанными.Загрузка = Истина. Это отключает выполнение прикладного кода в подписках на события и модулях объектов (процедуры ПередЗаписью, ПриЗаписи, ПередУдалением), существенно экономя процессорное время.Проанализируем частую ошибку оптимизации интерфейса. Разработчики часто вставляют в цикл удаления информационные сообщения для пользователя, например: Состояние("Удаление объекта " + Номер) на каждой итерации цикла. Замеры производительности показывают, что при удалении простых объектов (таких как штрихкоды или единицы измерения) на отрисовку прогресса и передачу данных между сервером и клиентом может уходить до 75% всего времени работы алгоритма!
Если вам необходимо выводить прогресс на экран, делайте это дискретно — например, раз в 5 000 или 10 000 удаленных элементов, используя оператор остатка от деления: Если Индекс % 5000 = 0 Тогда. А еще лучше — выполняйте удаление в фоновом задании на сервере без интерактивного взаимодействия с клиентом.
Если ваша база данных работает под управлением MS SQL Server или PostgreSQL, а удаляемые объекты гарантированно не имеют внешних связей (или вы сознательно берете на себя ответственность за ссылочную целостность), самым быстрым способом будет прямое удаление данных на уровне СУБД.
Для реализации этого метода выполним следующие шаги:
ПолучитьСтруктуруХраненияБазыДанных()._Reference125), необходимо также очистить таблицы табличных частей этого справочника (если они есть) и таблицы записей истории (если справочник версионируемый).Пример прямого SQL-запроса для очистки данных:
-- Прямое удаление данных на уровне MS SQL Server
-- ВНИМАНИЕ: Обязательно сделайте резервную копию базы перед выполнением!
-- Очищаем подчиненные табличные части (если они есть)
DELETE FROM _Reference125_VT1234 WHERE _Reference125_IDRRef IN
(SELECT _IDRRef FROM _Reference125 WHERE <Условие_на_удаление>);
-- Удаляем сами элементы справочника
DELETE FROM _Reference125 WHERE <Условие_на_удаление>;
Важное предупреждение: Использование прямых SQL-запросов для модификации данных нарушает лицензионное соглашение фирмы 1С и может привести к разрушению логической целостности базы данных. После выполнения таких операций на уровне СУБД в обязательном порядке запустите в 1С процедуру «Тестирование и исправление» (режим «Проверка ссылочной целостности -> Назначать ссылки/Очищать ссылки»).
Если ваша база данных файловая (формат 1CD) и перевести ее на SQL-версию нет технической возможности, главным узким местом при удалении миллионов записей будет скорость работы дисковой подсистемы. Запись логов транзакций файловой СУБД на медленный HDD или даже обычный SSD занимает много времени.
Мы можем временно обойти это аппаратное ограничение, используя RAM-диск (виртуальный диск, созданный в оперативной памяти компьютера):
1Cv8.1CD на созданный RAM-диск.1Cv8.1CD обратно на постоянный накопитель.Посмотрим на ситуацию с математической точки зрения. Если в вашем справочнике содержится 2.5 миллиона элементов, и вам нужно вычистить 2 миллиона из них, то эффективнее будет не удалять 80% базы данных, а сохранить оставшиеся 20%.
Этот подход переворачивает задачу с ног на голову и часто оказывается самым быстрым и безопасным. Рассмотрим этот алгоритм по шагам:
Удаление миллионов объектов из 1С — это комплексная задача, требующая понимания механизмов платформы и СУБД. Резюмируем ключевые правила, которые помогут вам сэкономить время:
ОбменДанными.Загрузка = Истина.