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