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

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

Работа с большими массивами данных в 1С часто сопряжена с проблемами производительности. Удаление даже 40 000 записей может затянуться на десятки минут, если использовать стандартные методы «в лоб». В этой статье мы подробно разберем, как оптимизировать процесс удаления, какие инструменты предоставляет платформа и как избежать блокировок системы при выполнении таких регламентных задач.

Причины низкой скорости удаления

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

  1. Чтение объекта: Платформа считывает все данные объекта (включая все реквизиты и все строки всех табличных частей) из базы данных в оперативную память.
  2. Проверка ссылочной целостности: Если не указано иное, система может проверять, нет ли ссылок на этот объект.
  3. Обработка событий модуля: Выполняются процедуры ПередУдалением и ПриУдалении.
  4. Подписки на события: В современных конфигурациях (ERP, УПП, КА) на справочники навешено множество внешних подписок, которые срабатывают при каждом удалении.
  5. Запись в лог транзакций: Каждое удаление фиксируется в журнале транзакций СУБД.

Рассмотрим способы, которые позволяют обойти эти ограничения.

Способ 1. Использование объекта УдалениеОбъекта и режима загрузки

Это самый сбалансированный способ, который остается в рамках идеологии 1С, но работает в разы быстрее стандартного удаления. Секрет заключается в использовании специального объекта УдалениеОбъекта и флага ОбменДанными.Загрузка = Истина.

Проанализируем пример кода, который позволяет ускорить процесс в 5-10 раз:


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

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

Способ 2. Оптимизация транзакций и пакетное удаление

При удалении 40к записей SQL-сервер может применить эскалацию блокировок, закрыв доступ к таблице для всех пользователей. Чтобы этого избежать, мы рекомендуем удалять данные порциями (пакетами) в рамках отдельных транзакций. Проанализируем ситуацию: если удалять по одной записи — это медленно из-за накладных расходов на транзакции. Если удалять всё одной транзакцией — это опасно блокировками. Оптимальный размер порции — от 1000 до 5000 записей.

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


Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.ИмяСправочника");
Результат = Запрос.Выполнить().Выгрузить();
ВсегоЗаписей = Результат.Количество();
РазмерПорции = 1000;
Счетчик = 0;

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

Важно: Такой подход позволяет другим пользователям работать с базой в перерывах между транзакциями и предотвращает бесконтрольный рост файла лога транзакций (LDF).

Способ 3. Использование нового метода УдалениеДанных (Платформа 8.3.23+)

В современных версиях платформы появился объект УдалениеДанных, предназначенный специально для массовых операций. Он работает максимально близко к уровню СУБД. Рассмотрим пример его использования:


МассивСсылок = Новый Массив; // Заполняем массив ссылками для удаления
Удаление = УдалениеДанных.Создать();
Удаление.Параметры.ВключатьПроверкуСсылочнойЦелостности = Ложь;
Удаление.Выполнить(МассивСсылок);

Этот метод оптимизирован внутри самой платформы и является наиболее современным решением для задач массовой очистки данных.

Способ 4. Прямое удаление через SQL (TRUNCATE и DELETE)

Если ваша база работает в клиент-серверном варианте и вы обладаете правами администратора СУБД, можно использовать команду TRUNCATE TABLE. Это самый быстрый способ во вселенной (занимает миллисекунды), так как он просто очищает страницы данных таблицы, не записывая удаление каждой строки в лог.

Однако здесь есть огромные риски, которые мы должны учитывать:

  1. Целостность данных: 1С ничего не узнает об удалении. Если на эти записи были ссылки в документах, вы получите «битые ссылки» (объект не найден).
  2. Табличные части: У справочника в SQL не одна таблица. Основная таблица имеет вид _ReferenceX, а табличные части — _ReferenceX_VT_Y. Команда TRUNCATE по основной таблице оставит «мусор» в таблицах ТЧ.
  3. Кэш: Сервер приложений 1С кэширует данные, и после удаления через SQL в интерфейсе могут продолжать отображаться «призраки» удаленных записей.

Поэтому метод через SQL (например, через ADODB.Connection) стоит использовать только в исключительных случаях, когда вы точно знаете, что ссылок на объект нет и структура таблиц вам полностью понятна.

Способ 5. Инструменты разработчика (ИР)

Для разовых задач очистки удобно использовать консоли из состава «Инструментов разработчика» (автор С. Старых). В них реализован функционал «Очистка таблиц СУБД», который автоматически находит все связанные таблицы справочника и выполняет их быструю очистку на уровне SQL, сохраняя при этом корректность структуры данных с точки зрения СУБД.

Рекомендации после массового удаления

Выясним, что нужно сделать после того, как 40 000 записей были успешно удалены. Массовое удаление создает «дыры» в индексах и таблицах, что может замедлить последующую работу.

Подводя итог, для большинства задач оптимальным выбором будет Способ 1 с использованием УдалениеОбъекта и Загрузка = Истина. Это безопасно, быстро и не требует глубоких знаний устройства SQL-таблиц.

← На главную