При работе с регистрами сведений в платформе 1С разработчики часто сталкиваются с задачей удаления части записей, попадающих под определенное условие — например, находящихся в диапазоне дат или соответствующих неключевым реквизитам. Однако стандартный объект платформы НаборЗаписей накладывает существенное ограничение: его отбор поддерживает исключительно строгое равенство по измерениям. Фильтрация по диапазону (операторы «между», «больше или равно», «меньше или равно») в объекте Отбор набора записей не поддерживается.
Разберем основные подходы к решению этой задачи, рассмотрим примеры программного кода и проанализируем нюансы производительности при работе с большими объемами данных.
Если объем регистра сведений относительно невелик (до нескольких десятков тысяч строк), наиболее простым и быстрым способом является получение всех строк, не подпадающих под условие удаления, с последующей полной перезаписью таблицы регистра.
Рассмотрим по шагам данный алгоритм:
НЕ ... МЕЖДУ ...).НаборЗаписей регистра без установки отборов.Записать() с замещением.Посмотрим на пример реализации данного подхода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| *
|ИЗ
| РегистрСведений.ТестовыйРегистр КАК ТестовыйРегистр
|ГДЕ
| НЕ (ТестовыйРегистр.ПредполагаемаяДатаДействия МЕЖДУ &ДатаНачала И &ДатаОкончания)";
Запрос.УстановитьПараметр("ДатаНачала", Дата("20150101000000"));
Запрос.УстановитьПараметр("ДатаОкончания", Дата("20151130235959"));
ТаблицаОставляемыхЗаписей = Запрос.Выполнить().Выгрузить();
НаборЗаписей = РегистрыСведений.ТестовыйРегистр.СоздатьНаборЗаписей();
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Загрузить(ТаблицаОставляемыхЗаписей);
НаборЗаписей.Записать(Истина);
Важное предостережение: этот способ категорически не подходит для больших регистров (сотни тысяч и миллионы строк). Выгрузка всей таблицы регистра в память сервера может привести к переполнению оперативной памяти и зависанию рабочего процесса, а полная блокировка таблицы при записи остановит работу пользователей всей информационной базы.
Для таблиц среднего и большого объема безопаснее сначала запросом отобрать именно те записи, которые необходимо удалить, получив значения всех ключевых измерений. Затем в цикле для каждой удаляемой строки устанавливается точечный отбор в наборе записей и выполняется запись пустого набора.
Разберем программный код точечного удаления:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТестовыйРегистр.Измерение1 КАК Измерение1,
| ТестовыйРегистр.Измерение2 КАК Измерение2,
| ТестовыйРегистр.ПредполагаемаяДатаДействия КАК ПредполагаемаяДатаДействия
|ИЗ
| РегистрСведений.ТестовыйРегистр КАК ТестовыйРегистр
|ГДЕ
| ТестовыйРегистр.ПредполагаемаяДатаДействия МЕЖДУ &ДатаНачала И &ДатаОкончания";
Запрос.УстановитьПараметр("ДатаНачала", Дата("20150101000000"));
Запрос.УстановитьПараметр("ДатаОкончания", Дата("20151130235959"));
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НаборЗаписей = РегистрыСведений.ТестовыйРегистр.СоздатьНаборЗаписей();
НаборЗаписей.ОбменДанными.Загрузка = Истина;
// Устанавливаем строгий отбор по всем измерениям записи
НаборЗаписей.Отбор.Измерение1.Установить(Выборка.Измерение1);
НаборЗаписей.Отбор.Измерение2.Установить(Выборка.Измерение2);
НаборЗаписей.Отбор.ПредполагаемаяДатаДействия.Установить(Выборка.ПредполагаемаяДатаДействия);
// Записываем пустой набор с замещением - запись удаляется
НаборЗаписей.Записать(Истина);
КонецЦикла;
Обратите внимание: перед записью не нужно вызывать метод Прочитать(). Пустой набор записей с установленным фильтром по всем измерениям при записи с параметром замещения Истина сразу удаляет соответствующую строку из базы данных.
Альтернативным способом построчного удаления является использование объекта МенеджерЗаписи. Этот метод делает код более компактным и наглядным:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
МенеджерЗаписи = РегистрыСведений.ТестовыйРегистр.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ОбменДанными.Загрузка = Истина;
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка);
МенеджерЗаписи.Удалить();
КонецЦикла;
Проанализируем ключевые правила, которые необходимо соблюдать при массовом удалении данных из регистров 1С:
ОбменДанными.Загрузка = Истина для набора или менеджера записи перед операцией удаления. Это предотвратит вызов лишнего кода в модуле набора записей, отключит подписки на события и не создаст избыточную нагрузку на планы обмена.ВЫБРАТЬ ПЕРВЫЕ 1000 ...) и оборачивайте удаление каждой порции в отдельную транзакцию через НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Это защитит СУБД от эскалации блокировок и переполнения журнала транзакций.ФоновыеЗадания, чтобы избежать обрыва соединения по таймауту и зависания пользовательского интерфейса.