Как выгружать записи регистра сведений порциями в Конвертации данных 2.1?

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

При организации обмена между конфигурациями 1С (например, между 1С:ERP и 1С:Розница) периодически возникает ситуация, когда объем зарегистрированных изменений в регистре сведений достигает сотен тысяч или даже миллионов записей. Типичный пример — регистры классификации и маркетинга (такие как НоменклатураСегментов), где пересчет динамических сегментов порождает лавинообразную регистрацию данных.

Если выгружать такой массив данных штатным механизмом в один файл, база-приемник тратит на разбор XML и запись наборов долгие часы, блокируя загрузку последующих оперативных изменений. Попытки просто ограничить количество записей через Отказ = Истина в стандартных обработчиках Правил выгрузки данных (ПВД) или Правил конвертации объектов (ПКО) приводят к критической ошибке: в сообщении обмена создаются пустые узлы наборов, а при квитировании (получении ответа от базы-приемника) регистрация изменений ошибочно снимается со всех записей, включая те, что не были переданы. Разберем причины такого поведения платформы и детально рассмотрим работающие способы решения проблемы.

Почему стандартный отбор в ПВД ломает квитирование изменений

Проанализируем механику работы планов обмена и подсистемы Конвертация данных 2.1:

  1. Формирование наборов: Записи регистра сведений выгружаются не изолированно, а в составе объектов РегистрСведенийНаборЗаписей. Если у регистра взведен флаг Основной отбор по всем измерениям, для каждой строки создается отдельный набор записей.
  2. Фиксация номеров сообщений: При стандартной выборке механизм обмена за один проход выбирает все зарегистрированные изменения узла и присваивает им текущий номер отправляемого сообщения (НомерОтправленного).
  3. Пропуск через Отказ: Когда в обработчике ПКО или ПВД выставляется флаг Отказ = Истина, платформа не отменяет факт того, что изменение уже включено в пакет обмена. В результате при получении подтверждения доставки от узла-приемника таблица изменений РегистрСведений.ИмяРегистра.Изменения очищается для всех записей с данным номером сообщения, и пропущенные данные навсегда теряются.

Способ 1. Программная выгрузка порциями и ручное квитирование наборов

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

Разберем по шагам логику решения:

  1. Запросом выбираем первые N записей из таблицы изменений регистра сведений (РегистрСведений.НоменклатураСегмента.Изменения).
  2. В запросе обязательно выполняем сортировку по полю НомерСообщения УБЫВ, чтобы в первую очередь повторно выгружались те изменения, которые уже отправлялись ранее, но еще не были подтверждены приемником.
  3. В цикле формируем РегистрСведенийНаборЗаписей, устанавливаем отборы по измерениям и считываем фактические данные методом Прочитать().
  4. Используем процедуру ВыгрузитьРегистр() для формирования корректного XML-узла набора (процедура ВыгрузитьПоПравилу() в данном случае неприменима, так как создает некорректный узел отдельной записи, вызывающий ошибку при загрузке).
  5. Вызываем метод ПланыОбмена.ВыбратьИзменения(), передавая в качестве фильтра конкретный НаборЗаписей. В этом случае номер отправленного сообщения проставляется исключительно для переданного набора, что сохраняет регистрацию для оставшихся в очереди записей.

Посмотрим на пример реализации в обработчике После выгрузки данных:


Узел = ПланыОбмена.ОбменУправлениеПредприятиемРозница.НайтиПоНаименованию("Розница, редакция 2.1 (2)");

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ ПЕРВЫЕ 10000
|	НоменклатураСегментаИзменения.Сегмент,
|	НоменклатураСегментаИзменения.Номенклатура,
|	НоменклатураСегментаИзменения.Характеристика,
|	НоменклатураСегментаИзменения.НомерСообщения
|ИЗ
|	РегистрСведений.НоменклатураСегмента.Изменения КАК НоменклатураСегментаИзменения
|ГДЕ
|	НоменклатураСегментаИзменения.Узел = &Узел
|
|УПОРЯДОЧИТЬ ПО
|	НоменклатураСегментаИзменения.НомерСообщения УБЫВ";

Запрос.УстановитьПараметр("Узел", Узел);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаТ = РезультатЗапроса.Выбрать();

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

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

Способ 2. Оптимизация структуры наборов через «Основной отбор»

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

Проанализируем настройку измерений регистра в конфигураторе:

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

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

Способ 3. Архитектурный перенос расчета на сторону базы-приемника

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

  1. Исключить регистр сведений НоменклатураСегментов из состава плана обмена.
  2. Передавать через правила обмена только сам справочник СегментыНоменклатуры с его настройками, фильтрами и схемами компоновки данных.
  3. На стороне базы-приемника включить типовое регламентное задание по формированию сегментов, которое выполнит локальный расчет состава сегментов в фоновом режиме без нагрузки на каналы передачи данных и подсистему синхронизации.
← На главную