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

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

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

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

Способ 1. Перезапись набора записей данными, которые необходимо оставить

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

Рассмотрим по шагам данный алгоритм:

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

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	*
    |ИЗ
    |	РегистрСведений.ТестовыйРегистр КАК ТестовыйРегистр
    |ГДЕ
    |	НЕ (ТестовыйРегистр.ПредполагаемаяДатаДействия МЕЖДУ &ДатаНачала И &ДатаОкончания)";

Запрос.УстановитьПараметр("ДатаНачала", Дата("20150101000000"));
Запрос.УстановитьПараметр("ДатаОкончания", Дата("20151130235959"));

ТаблицаОставляемыхЗаписей = Запрос.Выполнить().Выгрузить();

НаборЗаписей = РегистрыСведений.ТестовыйРегистр.СоздатьНаборЗаписей();
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Загрузить(ТаблицаОставляемыхЗаписей);
НаборЗаписей.Записать(Истина);

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

Способ 2. Выборка удаляемых записей и точечное удаление через набор записей

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

Разберем программный код точечного удаления:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТестовыйРегистр.Измерение1 КАК Измерение1,
    |	ТестовыйРегистр.Измерение2 КАК Измерение2,
    |	ТестовыйРегистр.ПредполагаемаяДатаДействия КАК ПредполагаемаяДатаДействия
    |ИЗ
    |	РегистрСведений.ТестовыйРегистр КАК ТестовыйРегистр
    |ГДЕ
    |	ТестовыйРегистр.ПредполагаемаяДатаДействия МЕЖДУ &ДатаНачала И &ДатаОкончания";

Запрос.УстановитьПараметр("ДатаНачала", Дата("20150101000000"));
Запрос.УстановитьПараметр("ДатаОкончания", Дата("20151130235959"));

Выборка = Запрос.Выполнить().Выбрать();

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

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

Способ 3. Использование Менеджера Записи

Альтернативным способом построчного удаления является использование объекта МенеджерЗаписи. Этот метод делает код более компактным и наглядным:


Выборка = Запрос.Выполнить().Выбрать();

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

Рекомендации по оптимизации и безопасной очистке данных

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

  1. Отключение проверок и подписок: Всегда устанавливайте свойство ОбменДанными.Загрузка = Истина для набора или менеджера записи перед операцией удаления. Это предотвратит вызов лишнего кода в модуле набора записей, отключит подписки на события и не создаст избыточную нагрузку на планы обмена.
  2. Удаление порциями в транзакциях: При очистке миллионов записей используйте выборку порциями (например, конструкцию ВЫБРАТЬ ПЕРВЫЕ 1000 ...) и оборачивайте удаление каждой порции в отдельную транзакцию через НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Это защитит СУБД от эскалации блокировок и переполнения журнала транзакций.
  3. Фоновое выполнение: Длительные операции очистки рекомендуется запускать в фоновом задании через объект ФоновыеЗадания, чтобы избежать обрыва соединения по таймауту и зависания пользовательского интерфейса.
← На главную