При организации обмена между конфигурациями 1С (например, между 1С:ERP и 1С:Розница) периодически возникает ситуация, когда объем зарегистрированных изменений в регистре сведений достигает сотен тысяч или даже миллионов записей. Типичный пример — регистры классификации и маркетинга (такие как НоменклатураСегментов), где пересчет динамических сегментов порождает лавинообразную регистрацию данных.
Если выгружать такой массив данных штатным механизмом в один файл, база-приемник тратит на разбор XML и запись наборов долгие часы, блокируя загрузку последующих оперативных изменений. Попытки просто ограничить количество записей через Отказ = Истина в стандартных обработчиках Правил выгрузки данных (ПВД) или Правил конвертации объектов (ПКО) приводят к критической ошибке: в сообщении обмена создаются пустые узлы наборов, а при квитировании (получении ответа от базы-приемника) регистрация изменений ошибочно снимается со всех записей, включая те, что не были переданы. Разберем причины такого поведения платформы и детально рассмотрим работающие способы решения проблемы.
Проанализируем механику работы планов обмена и подсистемы Конвертация данных 2.1:
РегистрСведенийНаборЗаписей. Если у регистра взведен флаг Основной отбор по всем измерениям, для каждой строки создается отдельный набор записей.НомерОтправленного).Отказ = Истина, платформа не отменяет факт того, что изменение уже включено в пакет обмена. В результате при получении подтверждения доставки от узла-приемника таблица изменений РегистрСведений.ИмяРегистра.Изменения очищается для всех записей с данным номером сообщения, и пропущенные данные навсегда теряются.Для того чтобы выгружать строго определенную порцию записей и не терять контроль над регистрацией изменений, отключим стандартное правило выгрузки данных (снимем флаг активности у ПВД соответствующего регистра) и реализуем алгоритм в обработчике После выгрузки данных.
Разберем по шагам логику решения:
N записей из таблицы изменений регистра сведений (РегистрСведений.НоменклатураСегмента.Изменения).НомерСообщения УБЫВ, чтобы в первую очередь повторно выгружались те изменения, которые уже отправлялись ранее, но еще не были подтверждены приемником.РегистрСведенийНаборЗаписей, устанавливаем отборы по измерениям и считываем фактические данные методом Прочитать().ВыгрузитьРегистр() для формирования корректного XML-узла набора (процедура ВыгрузитьПоПравилу() в данном случае неприменима, так как создает некорректный узел отдельной записи, вызывающий ошибку при загрузке).ПланыОбмена.ВыбратьИзменения(), передавая в качестве фильтра конкретный НаборЗаписей. В этом случае номер отправленного сообщения проставляется исключительно для переданного набора, что сохраняет регистрацию для оставшихся в очереди записей.Посмотрим на пример реализации в обработчике После выгрузки данных:
Узел = ПланыОбмена.ОбменУправлениеПредприятиемРозница.НайтиПоНаименованию("Розница, редакция 2.1 (2)");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10000
| НоменклатураСегментаИзменения.Сегмент,
| НоменклатураСегментаИзменения.Номенклатура,
| НоменклатураСегментаИзменения.Характеристика,
| НоменклатураСегментаИзменения.НомерСообщения
|ИЗ
| РегистрСведений.НоменклатураСегмента.Изменения КАК НоменклатураСегментаИзменения
|ГДЕ
| НоменклатураСегментаИзменения.Узел = &Узел
|
|УПОРЯДОЧИТЬ ПО
| НоменклатураСегментаИзменения.НомерСообщения УБЫВ";
Запрос.УстановитьПараметр("Узел", Узел);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаТ = РезультатЗапроса.Выбрать();
НаборЗаписей = РегистрыСведений.НоменклатураСегмента.СоздатьНаборЗаписей();
Пока ВыборкаТ.Следующий() Цикл
НаборЗаписей.Отбор.Сегмент.Установить(ВыборкаТ.Сегмент, Истина);
НаборЗаписей.Отбор.Номенклатура.Установить(ВыборкаТ.Номенклатура, Истина);
НаборЗаписей.Отбор.Характеристика.Установить(ВыборкаТ.Характеристика, Истина);
НаборЗаписей.Прочитать();
// Формируем корректный узел набора записей в XML
ВыгрузитьРегистр(НаборЗаписей, , , Истина, "НоменклатураСегмента");
// Фиксируем отправку только для данного набора записей
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, Узел.НомерОтправленного, НаборЗаписей);
КонецЦикла;
Рассмотрим альтернативный вариант, не требующий написания нестандартных обработчиков выборки. Зачастую низкая скорость загрузки связана не с общим объемом данных, а с огромным количеством единичных транзакций записи: 700 000 записей, переданных как 700 000 отдельных наборов, заставляют СУБД базы-приемника 700 000 раз перестраивать индексы и накладывать блокировки.
Проанализируем настройку измерений регистра в конфигураторе:
Сегмент, Номенклатура, Характеристика) стоит свойство Основной отбор, платформа дробит изменения до уровня единичной строки.Основной отбор с подчиненных измерений (Номенклатура и Характеристика), оставив его только у ведущего измерения Сегмент, изменения будут регистрироваться и выгружаться крупными наборами по сегментам целиком.НаборЗаписей.Записать() блочно для каждого сегмента, что ускоряет загрузку в десятки и сотни раз по сравнению с построчной обработкой.Важный нюанс: при снятии флага основного отбора изменение даже одного товара в сегменте приведет к регистрации и повторной выгрузке всего состава этого сегмента.
В типовых решениях (1С:ERP, 1С:Комплексная автоматизация, 1С:Розница) передача содержимого регистра НоменклатураСегментов через обмен данными зачастую является избыточной. Более эффективный подход:
НоменклатураСегментов из состава плана обмена.СегментыНоменклатуры с его настройками, фильтрами и схемами компоновки данных.