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

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

В процессе эксплуатации систем на базе 1С:Предприятие часто возникает задача очистки или частичного удаления данных из регистров сведений. Если объем данных исчисляется миллионами записей, стандартные методы могут работать крайне медленно или приводить к переполнению лога транзакций и блокировкам базы данных. В этой статье мы разберем наиболее эффективные способы очистки данных, проанализируем программные механизмы и выясним, как оптимизировать процесс удаления. Для тех, кто ищет готовое решение, существует универсальная обработка регистров сведений, которая позволяет выполнять удаление и замену записей по гибким фильтрам во всех конфигурациях — для этого подойдёт обработка для удаления данных и очистки регистров.

Анализ стандартного подхода и его ограничений

Рассмотрим стандартный способ очистки регистра через НаборЗаписей. При обычном подходе программисты часто используют метод Записать(Истина) для пустого набора записей. Однако, если регистр содержит огромный объем данных, попытка удалить всё за один раз может привести к тому, что SQL Server (или другая СУБД) не сможет выделить достаточно оперативной памяти для транзакции или произойдет ошибка тайм-аута. В некоторых случаях проблемы могут быть вызваны некорректными данными. Проанализируем, почему это происходит: при выполнении одной большой транзакции система блокирует таблицу, и все изменения записываются в лог транзакций. Чтобы избежать подобных проблем, лучше использовать инструменты удаления по отбору.

Метод пакетного удаления записей (порциями)

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

Посмотрим на пример кода, который реализует пакетное удаление:


Процедура УдалитьЗаписиПорциями(ИмяРегистра, РазмерПорции = 10000)
    РегистрМенеджер = РегистрыСведений[ИмяРегистра];
    
    Пока Истина Цикл
        // Выбираем только первые записи для удаления
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ ПЕРВЫЕ " + Формат(РазмерПорции, "ЧГ=0") + "
            |    *
            |ИЗ
            |    РегистрСведений." + ИмяРегистра + " КАК Рег";
        
        Результат = Запрос.Выполнить();
        Если Результат.Пустой() Тогда
            Прервать;
        КонецЕсли;
        
        Выборка = Результат.Выбрать();
        
        // Используем транзакцию для каждой порции
        НачатьТранзакцию();
        Попытка
            Пока Выборка.Следующий() Цикл
                Набор = РегистрМенеджер.СоздатьНаборЗаписей();
                // Устанавливаем фильтры по измерениям
                Для Каждого Измерение Из РегистрМенеджер.Метаданные().Измерения Цикл
                    Набор.Отбор[Измерение.Имя].Установить(Выборка[Измерение.Имя]);
                КонецЦикла;
                
                Набор.Записать();
            КонецЦикла;
            ЗафиксироватьТранзакцию();
        Исключение
            ОтменитьТранзакцию();
            ЗаписьЖурналаРегистрации("Удаление", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
            Прервать;
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

В данном примере мы используем объект НаборЗаписей для каждой конкретной строки. Однако для независимых регистров сведений существует еще более быстрый способ очистки — использование пустого набора с фильтрацией по ведущим измерениям или периоду.

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

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

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

Эффективное удаление по измерениям

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

Пример кода для быстрого удаления данных по фильтру:


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

// Важный момент: включаем режим загрузки
Набор.ОбменДанными.Загрузка = Истина;

// Записываем пустой набор, что фактически удаляет записи, 
// подходящие под установленный отбор
Набор.Записать(Истина);

Использование объектной модели против прямого удаления

Выясним причину, по которой иногда стоит использовать МенеджерЗаписи. Если вам нужно удалять записи точечно в процессе сложного перебора, МенеджерЗаписи может показаться удобнее. Но помните, что для массовых операций НаборЗаписей всегда будет производительнее.

Рекомендации по работе с большими объемами данных

Подводя итог нашему анализу, сформируем список правил для максимально быстрого удаления данных в 1С:Предприятие 8.3:

  1. Всегда используйте пакетную обработку. Не пытайтесь удалить миллион записей в одной транзакции. Оптимальный размер порции обычно составляет от 1 000 до 10 000 записей.
  2. Отключайте обработчики событий. Обязательно устанавливайте ОбменДанными.Загрузка = Истина для объекта НаборЗаписей.
  3. Следите за индексами. Удаление по измерениям, которые не входят в индекс, будет происходить значительно медленнее, так как СУБД придется выполнять полное сканирование таблицы (Full Scan).
  4. Минимизируйте использование блокировок. Если возможно, выполняйте удаление в периоды минимальной активности пользователей или через фоновые задания, чтобы не мешать оперативной работе в базе.
  5. Проверяйте лог транзакций. При массовом удалении на сервере SQL может закончиться место под ldf файл. Пакетное удаление с фиксацией транзакций после каждой порции решает эту проблему.

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


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

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

← На главную