Переход с конфигурации «Управление производственным предприятием» (УПП 1.3) на «Зарплата и управление персоналом» (ЗУП 3.1) часто сопровождается переносом накопленных исторических данных. Одной из наиболее тяжелых операций становится перенос документов Табель учета рабочего времени. В УПП 1.3 структура табличной части документа состоит из 248 горизонтальных колонок на каждого сотрудника (31 день × 4 вида времени и часов). В ЗУП 3.1 структура табличной части вертикальная: каждая запись по виду времени превращается в отдельную строку.
При использовании стандартного вызова функции ВыгрузитьПоПравилу внутри обработчиков правил выгрузки данных (ПВД) выгрузка даже одного месяца может занимать десятки часов или приводить к вылету платформы из-за нехватки оперативной памяти. Рассмотрим подробно причины медленной работы и разберем по шагам, как оптимизировать процесс выгрузки.
Проанализируем стандартные ошибки, которые допускаются при написании правил в конфигурации «Конвертация данных 2.1»:
ТабельУчетаРабочегоВремениОрганизацииОтработанноеВремя. Это генерирует тысячи отдельных обращений к СУБД.Новый ТаблицаЗначений и Скопировать() на каждом шаге цикла приводит к фрагментации оперативной памяти и интенсивной работе сборщика мусора 1С.ВыгрузитьПоПравилу движок Конвертации данных выполняет поиск и проверку ссылок на физические лица, сотрудники и виды использования рабочего времени.Рассмотрим пример исходного медленного кода с запросом в цикле:
Для каждого докТабеля Из ТЗ Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТабельОтработанноеВремя.Сотрудник,
| ТабельОтработанноеВремя.ПервыйВидВремени1,
| ТабельОтработанноеВремя.ПервыйЧасов1
|ИЗ
| Документ.ТабельУчетаРабочегоВремениОрганизации.ОтработанноеВремя КАК ТабельОтработанноеВремя
|ГДЕ
| ТабельОтработанноеВремя.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", докТабеля.Ссылка);
ВыборкаВремени = Запрос.Выполнить().Выбрать();
Пока ВыборкаВремени.Следующий() Цикл
// Добавление строк и ручной перебор 248 колонок
КонецЦикла;
ВыгрузитьПоПравилу(докТабеля, , , , "ТабельУчетаРабочегоВремени");
КонецЦикла;
Чтобы ускорить процесс, перенесем логику с ПВД на правило конвертации объектов (ПКО). Создадим ПКО для документа, а для табличной части настроим правило конвертации группы свойств (ПКГС). В обработчике ПКГС ПередОбработкой сформируем коллекцию объектов единым запросом через КоллекцияОбъектов.
Разберем по шагам, как трансформировать горизонтальную структуру УПП в вертикальную структуру ЗУП прямо в тексте запроса с помощью секций ОБЪЕДИНИТЬ ВСЕ. Это позволит переложить всю тяжелую работу по разворачиванию 248 колонок на СУБД:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЧ.Ссылка КАК Ссылка,
| ТЧ.Сотрудник КАК Сотрудник,
| ТЧ.ПервыйВидВремени1 КАК ВидВремени,
| ТЧ.ПервыйЧасов1 КАК Часов,
| 1 КАК День
|ИЗ
| Документ.ТабельУчетаРабочегоВремениОрганизации.ОтработанноеВремя КАК ТЧ
|ГДЕ
| ТЧ.Ссылка = &Источник
| И ТЧ.ПервыйВидВремени1 НЕ ЗНАЧЕНИЕ(Справочник.КлассификаторИспользованияРабочегоВремени.ПустаяСсылка)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ТЧ.Ссылка,
| ТЧ.Сотрудник,
| ТЧ.ВторойВидВремени1,
| ТЧ.ВторойЧасов1,
| 1
|ИЗ
| Документ.ТабельУчетаРабочегоВремениОрганизации.ОтработанноеВремя КАК ТЧ
|ГДЕ
| ТЧ.Ссылка = &Источник
| И ТЧ.ВторойВидВремени1 НЕ ЗНАЧЕНИЕ(Справочник.КлассификаторИспользованияРабочегоВремени.ПустаяСсылка)";
Запрос.УстановитьПараметр("Источник", Источник);
КоллекцияОбъектов = Запрос.Выполнить().Выгрузить();
Преимущества подхода:
ГДЕ запроса, что сокращает передаваемый объем данных в 3–4 раза.Если выборка всех документов за несколько лет не помещается в оперативную память и приводит к аварийному завершению работы 1С, необходимо организовать порционную выгрузку. Разберем, как выгружать данные пакетами по 50–100 документов за один раз.
В ПВД формируем список ссылок на документы и разбиваем их на порции, передавая массив ссылок в параметр запроса:
ЗапросДокументы = Новый Запрос;
ЗапросДокументы.Текст =
"ВЫБРАТЬ
| Табель.Ссылка КАК Ссылка
|ИЗ
| Документ.ТабельУчетаРабочегоВремениОрганизации КАК Табель
|ГДЕ
| Табель.Проведен
| И Табель.Дата МЕЖДУ &ДатаНач И &ДатаКон";
ЗапросДокументы.УстановитьПараметр("ДатаНач", ДатаНачала);
ЗапросДокументы.УстановитьПараметр("ДатаКон", ДатаОкончания);
ВыборкаДокументов = ЗапросДокументы.Выполнить().Выбрать();
МассивПорции = Новый Массив;
Счетчик = 0;
Пока ВыборкаДокументов.Следующий() Цикл
МассивПорции.Добавить(ВыборкаДокументов.Ссылка);
Счетчик = Счетчик + 1;
Если Счетчик >= 100 Тогда
ВыгрузитьПакетТабелей(МассивПорции);
МассивПорции.Очистить();
Счетчик = 0;
КонецЕсли;
КонецЦикла;
Если МассивПорции.Количество() > 0 Тогда
ВыгрузитьПакетТабелей(МассивПорции);
КонецЕсли;
В функции ВыгрузитьПакетТабелей выполняем один запрос к табличным частям всех документов из массива, что исключает проблему выполнения запроса в цикле по каждому документу отдельно.
Для максимально быстрой выгрузки больших массивов данных можно полностью отказаться от движка Конвертации данных и сформировать XML-файл вручную с помощью объекта ЗаписьXML.
Рассмотрим алгоритм действий:
ЗаписьXML, выгружая только необходимые реквизиты (GUID объектов, даты, сотрудников, виды времени и часы).ЧтениеXML считываем файл и создаем документы программно через Документы.Табель.СоздатьДокумент().Пример формирования файла на стороне источнике:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Export\tabels.xml");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеТабелей");
// Обход выборки и запись структур
ЗаписьXML.ЗаписатьНачалоЭлемента("Документ");
ЗаписьXML.ЗаписатьАтрибут("GUID", Строка(СсылкаНаДок.УникальныйИдентификатор()));
ЗаписьXML.ЗаписатьАтрибут("Дата", Формат(СсылкаНаДок.Дата, "ДФ=ггггММддHHmmss"));
// Запись строк времени
ЗаписьXML.ЗаписатьНачалоЭлемента("СтрокаВремени");
ЗаписьXML.ЗаписатьАтрибут("СотрудникGUID", Строка(СотрудникGUID));
ЗаписьXML.ЗаписатьАтрибут("Часы", Строка(Часов));
ЗаписьXML.ЗаписатьКонецЭлемента(); // СтрокаВремени
ЗаписьXML.ЗаписатьКонецЭлемента(); // Документ
ЗаписьXML.ЗаписатьКонецЭлемента(); // ДанныеТабелей
ЗаписьXML.Закрыть();
Этот способ работает в десятки раз быстрее КД 2.1, так как исключает накладные расходы на универсальные механизмы конвертации, проверку правил сопоставления и заполнение промежуточных деревьев свойств.