Как существенно ускорить удаление большого количества объектов в 1С:Предприятие 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработчика 1С часто возникает задача очистки базы данных от устаревших или ошибочно созданных записей. Когда речь идет о нескольких десятках объектов, стандартные инструменты справляются без проблем. Однако при необходимости удалить сотни тысяч или миллионы строк, стандартная обработка "Удаление помеченных объектов" может работать часы или даже сутки, полностью блокируя работу пользователей. В рамках данной статьи мы проанализируем ситуацию, разберем причины медленной работы и рассмотрим эффективные программные методы ускорения этого процесса.

Выясним причину: почему стандартное удаление работает медленно?

Прежде чем переходить к коду, давайте разберем, что происходит "под капотом" системы 1С при удалении объекта. Основные временные затраты уходят на следующие операции:

  1. Проверка ссылочной целостности: Система ищет упоминания удаляемого объекта во всех таблицах базы данных. Если объект используется в каком-либо документе или регистре, удаление будет заблокировано.
  2. Выполнение подписок на события: При удалении срабатывают обработчики ПередУдалением и ПриУдалении, которые могут содержать тяжелую бизнес-логику.
  3. Обновление индексов: Каждое удаление приводит к перестроению индексов таблиц в СУБД.
  4. Запись в журнал регистрации: Фиксация каждого действия замедляет процесс, особенно при огромных объемах.

Способ №1: Использование метода УдалитьОбъекты с отключением проверок

Рассмотрим самый быстрый штатный метод платформы — использование глобальной функции УдалитьОбъекты(). Этот метод позволяет передать массив ссылок и указать параметры проверки ссылочной целостности. Проанализируем пример кода, который позволяет обойти большинство стандартных проверок:


МассивСсылок = Новый Массив;
// Предположим, мы заранее собрали ссылки на объекты, которые нужно удалить
// Например, через запрос по пометке удаления
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура ГДЕ ПометкаУдаления = ИСТИНА");
Результат = Запрос.Выполнить();
МассивСсылок = Результат.Выгрузить().ВыгрузитьКолонку("Ссылка");

// Удаляем объекты без проверки ссылочной целостности
// Второй параметр Ложь отключает проверку контроля ссылок
УдалитьОбъекты(МассивСсылок, Ложь);

Важный момент: использование данного метода с параметром Ложь крайне опасно, так как в базе могут остаться "битые" ссылки (объект удален, а ссылка на него в других документах осталась). Мы рекомендуем использовать этот метод только в тех случаях, когда вы абсолютно уверены, что на данные объекты нет ссылок, или планируете провести последующее исправление связей.

Способ №2: Оптимизация через режим загрузки данных

Если нам необходимо программно удалять объекты в цикле (например, при сложной фильтрации), мы можем использовать свойство ОбменДанными.Загрузка. Рассмотрим, как это работает. Установка этого свойства в значение Истина сообщает платформе, что выполняется перенос данных, и большинство прикладных проверок в модулях объектов и подписках на события выполнять не нужно.

Разберем по шагам алгоритм удаления с использованием этого механизма:


Для Каждого СсылкаИзСписка Из СписокКУдалению Цикл
    ОбъектОбъект = СсылкаИзСписка.ПолучитьОбъект();
    Если ОбъектОбъект <> Неопределено Тогда
        // Отключаем проверки бизнес-логики
        ОбъектОбъект.ОбменДанными.Загрузка = Истина;
        Попытка
            ОбъектОбъект.Удалить();
        Исключение
            ЗаписатьЛогОшибки("Не удалось удалить объект: " + СсылкаИзСписка);
        КонецПопытки;
    КонецЕсли;
КонецЦикла;

Этот подход значительно ускоряет процесс за счет того, что 1С не тратит время на выполнение кода в модулях, который обычно проверяет корректность удаления с точки зрения бизнес-логики предприятия.

Способ №3: Пакетная обработка в транзакциях и фоновые задания

Проанализируем ситуацию, когда объектов слишком много для одного сеанса. Основная проблема здесь — блокировка таблиц. Чтобы минимизировать влияние на работу других пользователей и ускорить процесс, мы применим стратегию пакетного удаления в транзакциях. Мы будем удалять данные порциями, например, по 1000 объектов в одной транзакции.

Посмотрим на пример реализации такого механизма:


Процедура УдалитьПакетно(МассивСсылок)
    РазмерПакета = 1000;
    ВсегоОбъектов = МассивСсылок.Количество();
    ТекущийИндекс = 0;

    Пока ТекущийИндекс < ВсегоОбъектов Цикл
        НачатьТранзакцию();
        Попытка
            Для Счетчик = 1 По РазмерПакета Цикл
                Если ТекущийИндекс >= ВсегоОбъектов Тогда
                    Прервать;
                КонецЕсли;
                
                СсылкаДляУдаления = МассивСсылок[ТекущийИндекс];
                // Вызываем удаление без проверок (или с ними, если нужно)
                УдалитьОбъекты(Новый Массив(СсылкаДляУдаления), Ложь);
                
                ТекущийИндекс = ТекущийИндекс + 1;
            КонецЦикла;
            ЗафиксироватьТранзакцию();
        Исключение
            ОтменитьТранзакцию();
            // Логируем ошибку и продолжаем со следующего пакета
            ТекущийИндекс = ТекущийИндекс + 1; 
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Использование транзакций позволяет СУБД более эффективно записывать изменения на диск, а ограничение размера пакета предотвращает чрезмерное разрастание лога транзакций и блокировку всей таблицы на длительное время.

Особенности удаления записей из регистров сведений

Если ваша задача заключается в очистке регистра сведений (например, логов или версий объектов), метод Удалить() для каждой записи будет крайне медленным. Вместо этого мы рекомендуем использовать НаборЗаписей. Чтобы полностью очистить регистр или его часть по фильтру, достаточно записать пустой набор записей с установленным отбором.

Рассмотрим пример очистки регистра по конкретному измерению:


Набор = РегистрыСведений.ИсторияИзменений.СоздатьНаборЗаписей();
// Устанавливаем фильтр, чтобы не удалить лишнего
Набор.Отбор.Объект.Установить(СсылкаНаОбъект);
// Очищаем набор (не добавляем в него записи)
// Записываем пустой набор, что фактически удаляет записи из базы
Набор.Записать(Истина);

Этот метод работает на порядок быстрее, так как платформа выполняет одну операцию DELETE в базе данных для всего диапазона записей, попадающих под фильтр.

Практические советы по организации процесса

Чтобы процесс удаления прошел максимально гладко, мы рекомендуем придерживаться следующих правил:

Подводя итог, можно сказать, что ключом к быстрому удалению данных в 1С является сочетание трех факторов: отключение лишних проверок через ОбменДанными.Загрузка, использование пакетных транзакций и применение специализированных методов типа пустого набора записей для регистров. Проанализировав ваши потребности и выбрав правильный инструмент, вы сможете сократить время обслуживания базы в десятки раз.

← На главную