Как быстро удалить большое количество элементов из справочника в 1С

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

В процессе разработки на платформе 1С:Предприятие часто возникает задача полной очистки справочника перед загрузкой новых данных. Когда количество элементов исчисляется десятками тысяч (например, 20 000 и более), стандартные методы удаления в цикле могут работать крайне медленно. В этой статье мы подробно проанализируем, почему возникает эта проблема, и рассмотрим несколько эффективных способов её решения.

Анализ проблемы производительности

Рассмотрим стандартный подход, который часто выбирают начинающие специалисты. В коде выполняется запрос к справочнику, получается выборка, и в цикле для каждой ссылки вызывается метод ПолучитьОбъект().Удалить(). Основная причина низкой скорости здесь заключается в методе ПолучитьОбъект(). Проанализируем ситуацию: для удаления 20 000 элементов система должна 20 000 раз обратиться к базе данных, чтобы считать полные данные каждого объекта в память сервера, и только после этого выполнить команду удаления. Если справочник имеет тяжелые табличные части или множество реквизитов, время выполнения операции возрастает в геометрической прогрессии.

Оптимизация с использованием флага ОбменДанными.Загрузка

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

Выясним, как изменить код для использования этого преимущества:


&НаСервере
Процедура ОчиститьСправочникОптимизировано()
    Выборка = Справочники.ФедеральныеЛьготники.Выбрать();
    Пока Выборка.Следующий() Цикл
        Объект = Выборка.Ссылка.ПолучитьОбъект();
        Если Объект <> Неопределено Тогда
            Объект.ОбменДанными.Загрузка = Истина;
            Объект.Удалить();
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

Пакетное удаление в транзакциях

Разберем вопрос использования транзакций. Работа с базой данных без явного открытия транзакции заставляет СУБД (MS SQL, PostgreSQL) фиксировать каждое удаление как отдельную операцию в логе транзакций. Это создает колоссальную нагрузку на дисковую подсистему. Однако слишком большая транзакция (на все 20 000 элементов) может привести к переполнению лога или блокировке всей таблицы справочника на длительное время.

Оптимальным решением будет удаление порциями (пакетами). Посмотрим на пример кода, реализующего этот подход:


&НаСервере
Процедура УдалитьПакетами()
    Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.ФедеральныеЛьготники");
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Счетчик = 0;
    НачатьТранзакцию();
    
    Пока Выборка.Следующий() Цикл
        СпрОбъект = Выборка.Ссылка.ПолучитьОбъект();
        Если СпрОбъект <> Неопределено Тогда
            СпрОбъект.ОбменДанными.Загрузка = Истина;
            СпрОбъект.Удалить();
            Счетчик = Счетчик + 1;
        КонецЕсли;
        
        // Фиксируем транзакцию каждые 1000 элементов
        Если Счетчик % 1000 = 0 Тогда
            ЗафиксироватьТранзакцию();
            НачатьТранзакцию();
        КонецЕсли;
    КонецЦикла;
    
    Если ТранзакцияАктивна() Тогда
        ЗафиксироватьТранзакцию();
    КонецЕсли;
КонецПроцедуры

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

Проблема ссылочной целостности

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

Если справочник используется только для временного отображения данных и гарантированно не связан с другими объектами системы, непосредственное удаление допустимо. В противном случае лучше использовать метод УстановитьПометкуУдаления(Истина), который работает быстрее, чем полное удаление, но оставляет возможность корректной очистки через стандартные механизмы контроля целостности.

Архитектурное решение: замена Справочника на Регистр сведений

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

  1. Для полной очистки регистра не нужно перебирать записи в цикле.
  2. Метод НаборЗаписей.Записать(Истина) с пустым набором мгновенно очищает таблицу на уровне СУБД.
  3. В регистре нет системных полей Ссылка, Код, Наименование, что делает таблицу "легче".

Пример мгновенной очистки регистра:


Набор = РегистрыСведений.ФедеральныеЛьготникиДанные.СоздатьНаборЗаписей();
// Пустой набор при записи с параметром Истина затирает все данные
Набор.Записать(Истина);

Для 20 000 записей эта операция займет доли секунды, в то время как удаление из справочника в любом случае потребует нескольких минут.

Фоновое выполнение операций

Чтобы пользователь не видел "зависшее" окно программы во время удаления и загрузки, крайне рекомендуется выносить эти процедуры в Фоновое задание. Рассмотрим основные шаги:

  1. Создайте в общем модуле процедуру, выполняющую очистку и загрузку.
  2. Используйте метод ФоновыеЗадания.Выполнить() для запуска процесса.
  3. На форме используйте ПодключитьОбработчикОжидания для проверки статуса задания и оповещения пользователя о завершении.

Это позволит пользователю продолжать работу с другими разделами программы, пока сервер обрабатывает большой массив данных.

Использование прямых SQL-запросов (TRUNCATE)

Для опытных администраторов существует радикальный способ — выполнение команды TRUNCATE TABLE непосредственно в базе данных. Это мгновенная операция, которая полностью очищает таблицу. Однако мы не рекомендуем этот метод начинающим специалистам по нескольким причинам:

Итоговые рекомендации

Подводя итоги, выделим лучший алгоритм действий для быстрой очистки данных:

  1. Если данные временные и на них нет ссылок — рассмотрите возможность использования Регистра сведений.
  2. Если необходим именно справочник, используйте удаление с установкой флага ОбменДанными.Загрузка = Истина.
  3. Обязательно объединяйте операции удаления в транзакции по 1000-2000 элементов.
  4. Запускайте процесс в фоновом задании, чтобы обеспечить комфортную работу пользователя.
  5. Выполняйте код в привилегированном модуле, чтобы исключить замедление из-за проверок RLS (прав доступа на уровне записей).

Следуя этим правилам, вы сможете сократить время обработки справочника с нескольких часов до нескольких минут или даже секунд.

← На главную