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

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

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

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

Рассмотрим стандартный подход, который часто выбирают начинающие специалисты. В коде выполняется запрос к справочнику, получается выборка, и в цикле для каждой ссылки вызывается метод ПолучитьОбъект().Удалить(). Основная причина низкой скорости здесь заключается в методе ПолучитьОбъект(). Проанализируем ситуацию: для удаления 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. Запускайте процесс в фоновом задании, чтобы обеспечить комфортную работу пользователя. При необходимости сократить объем исторических записей в крупных базах используется многопоточная свёртка 1С:ERP в несколько параллельных потоков.
  5. Выполняйте код в привилегированном модуле, чтобы исключить замедление из-за проверок RLS (прав доступа на уровне записей).

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

← На главную