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