Довольно часто разработчики сталкиваются с ситуацией, когда сложный отчет на базе системы компоновки данных (СКД) в конфигурациях на платформе 1С:Предприятие 8.3 (например, 1С:Управление торговлей 11) формируется несколько минут. При этом проверка исходного текста запроса в консоли запросов показывает моментальный результат — от 2 до 5 секунд. Разберем детально, почему возникает такая разница в производительности, где на самом деле теряется время и какими способами можно ускорить формирование отчета.
Если текст запроса идентичен, а время исполнения отличается в десятки раз, задержка кроется не в выборке данных СУБД, а во внутренних механизмах платформы 1С и СКД. Проанализируем основные факторы:
ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент занимает значительную часть времени, если включен автоматический расчет ширины колонок, перенос текста по словам, автовысота строк или сложное условное оформление.Если отчет содержит специфическую логику или СКД выполняет избыточные трансформации запроса, эффективным решением является предварительное выполнение запроса средствами встроенного языка 1С, выгрузка результата в объект ТаблицаЗначений и передача этой таблицы в СКД в качестве внешнего набора данных. В этом случае за СКД остается только вывод в макет и управление оформлением.
Рассмотрим пример программного формирования отчета через внешний набор данных:
// Создаем и выполняем исходный запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.Склад КАК Склад,
| ТоварыНаСкладахОстатки.ВНаличииОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("Период", ТекущаяДата());
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
// Подготавливаем компоновку данных
СхемаКомпоновки = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаКомпоновки.НастройкиПоУмолчанию;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// Заполняем внешний набор данных
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("НаборДанныхТаблица", ТаблицаДанных);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
ТабличныйДокумент = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Такой подход исключает вмешательство СКД в оптимизацию запроса и существенно сокращает время выполнения.
Если требуется сохранить стандартную работу отчета без перехода на внешние наборы данных, проанализируем настройки самой схемы компоновки:
ПРЕДСТАВЛЕНИЕ(ПолеСсылка) или обращайтесь к реквизиту напрямую (например, Номенклатура.Наименование КАК НоменклатураНаименование).Чтобы точно определить, на каком шаге происходит замедление, выполним замер производительности программного кода компоновки. Разделим процесс на ключевые операции:
// Шаг 1: Формирование макета компоновки
ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки());
ВремяМакета = ТекущаяУниверсальнаяДатаВМиллисекундах() - ВремяНачала;
// Шаг 2: Инициализация процессора компоновки и выборка данных
ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ВремяИнициализации = ТекущаяУниверсальнаяДатаВМиллисекундах() - ВремяНачала;
// Шаг 3: Вывод данных в результирующий табличный документ
ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
ВремяВывода = ТекущаяУниверсальнаяДатаВМиллисекундах() - ВремяНачала;
ЗаписьЖурналаРегистрации("ЗамерСКД", УровеньЖурналаРегистрации.Информация,,,
СтрШаблон("Макет: %1 мс, Инициализация: %2 мс, Вывод: %3 мс", ВремяМакета, ВремяИнициализации, ВремяВывода));
Если задержка сосредоточена на этапе вывода (ПроцессорВывода.Вывести()), проблема заключается в отрисовке ячеек и оформлении. Если на этапе инициализации — дело в неявных запросах или медленной обработке итогов платформой.
Если программный замер показывает, что сам код СКД выполняется быстро, а общее время ожидания в пользовательском интерфейсе велико, проверим системное окружение:
srvinfo и системный каталог временных файлов операционной системы (папка Temp пользователя, под которым работает служба ragent) добавлены в исключения антивирусного сканера.