Итак, начнем с того, что включим Замер производительности из Конфигуратора при печати табеля. Находим узкое место, благо, что оно есть, и ставим там точку остановки.
Запускаем печать табеля ещё раз, попадаем на точку остановки, жмём Shift-F9 (или Меню - Отладка - Вычислить выражение), выполняем команду:
"ВнешниеОбработки.Создать("<Путь к вашему ИР>\ирПортативный.epf", Ложь).От(ЗапросТабель)",
открываем консоль с запросом. Можно, на всякий случай, сохранить его в файл. В консоли запускаем запрос на выполнение,
перейдем на закладку "Запрос результат", нажмем пункт меню "Статистика MSSQL"
Здесь, возможно, придется ввести данные для доступа к MSSQL. Важно не перепутать, вводим администраторские данные для входа именно в MSSQL, а не 1С
Мы получим список всех запросов, которые выполнились во время работы нашего суперзапроса. Находим среди них самый тяжелый (например, по столбцу Tot CPU Time) щелкаем на нем, далее Открыть план,
смотрим на План выполнения запроса и.... ничего интересного я там не нашел, индексы на месте.
Ладно, пойдем другим путем. Смотрим на текст запроса в столбце "Текст запроса мета" и находим этот кусок в главном тексте запроса. В нашем случае, это создание таблицы "ВТГрафикиРаботыПоВидамВремени".
Глаз сразу цепляется за "Объединить все" в подзапросе. Вспоминаем по многочисленным публикациям, что подзапрос должен быть как можно проще, желательно одна небольшая временная таблица.
ОК, так и сделаем. Создадим на всякий случай копию запроса и уже там заменим объединение двух временных таблиц на одну новую. Можно сделать это руками, но мы воспользуемся возможностями инструмента "Конструктор запроса ИР".
Найдем слева нашу таблицу "ВТГрафикиРаботыПоВидамВремени", справа отбор. Провалимся в наш отбор и преобразуем Запрос во временную таблицу
Долее, все сохраняем (Ок - Ок), запускаем на исполнение и вуаля, ускорение более, чем в 3 раза в консоли запроса.
В Замере производительности
Внимание, во время манипуляций "Консоль запроса ИР" проставит кучу мусорных условий типа "Истина И". И я не знаю, как их разом убрать.
Табель побольше, другая организация
Проверим другой табель. Сначала всё то же самое, узкое место в этой же строке. Пройдя по проторенной дорожке, найдем медленный запрос. Здесь это уже другой запрос, смотрим его план выполнения.
Бросается в глаза большой объем передаваемых данных, полмиллиона записей в небольшом табеле. По аналогии, находим нужное место в тексте запроса, это создание временной таблицы "ВТНеобработанныеПлановыеНачисленияРаботниковОрганизаций".
Там мы видим слабый фильтр по огромному регистру ПлановыеНачисленияРаботниковОрганизаций -
"И ПлановыеНачисленияРаботниковОрганизаций.Период <= &КонецПериода".
Отфильтруем старые недействующие, плановые начисления с признаком Прекратить.
"И ПлановыеНачисленияРаботниковОрганизаций.Период <= &КонецПериода
И НЕ(ПлановыеНачисленияРаботниковОрганизаций.ПериодЗавершения < &НачалоПериода
И ПлановыеНачисленияРаботниковОрганизаций.ДействиеЗавершения = ЗНАЧЕНИЕ(Перечисление.ВидыДействияСНачислением.Прекратить))"
Поток данных снизился
выигрыш составил 4 секунды.
Вау, мы великолепны? Нет, мы ещё не рассмотрели самые большие табели.
Самый большой табель.
На больших табелях эффект от нашей оптимизации почти незаметен, так как узким местом является другая строка.
Это известная проблема метода ПроверитьВывод. Есть хорошее описание и способы решения на здесь на ИС . Идея в том, что завести еще один, вспомогательный Табличный документ и проверять вывод на нем и регулярно очищать его. Потому что, на больших табличных документах проверка вывода идет намного-намного, просто экспоненциально медленнее.
Итак, в начале процедуры "СформироватьМакет" создаем новый Табличный документ
Если Не ПроцедурыУправленияПерсоналомПереопределяемый.РегламентированныйКалендарьЗаполнен(НачалоПериода, КонецПериода, Истина) Тогда
Если Режим = "Табель" Тогда
Возврат;
КонецЕсли;
КонецЕсли;
ДокументРезультат.Очистить();
///+++
_ДокументРезультат = Новый ТабличныйДокумент;
ЗаполнитьЗначенияСвойств(_ДокументРезультат, ДокументРезультат);
///+++
Везде, где встречается "ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();" добавляем две строки
Если Не ФормированиеПечатныхФорм.ПроверитьВыводТабличногоДокумента(ДокументРезультат, ОбластьДанныхСтрока) Тогда
ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();
///+++
_ДокументРезультат.Вывести(ДокументРезультат);
ДокументРезультат.Очистить();
///+++
ДокументРезультат.Вывести(ОбластьДанныхКолонтитул);
КонецЕсли;
Если Не ФормированиеПечатныхФорм.ПроверитьВыводТабличногоДокумента(ДокументРезультат, ОбластьДанныхПодвал) Тогда
ПоследняяСтрокаЛиста = ДокументРезультат.ПолучитьОбласть(ДокументРезультат.ВысотаТаблицы - 3,,ДокументРезультат.ВысотаТаблицы,);
ДокументРезультат.УдалитьОбласть(ДокументРезультат.Область(ДокументРезультат.ВысотаТаблицы - 3,,ДокументРезультат.ВысотаТаблицы,),);
ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();
///+++
_ДокументРезультат.Вывести(ДокументРезультат);
ДокументРезультат.Очистить();
///+++
ДокументРезультат.Вывести(ОбластьДанныхКолонтитул);
ДокументРезультат.Вывести(ПоследняяСтрокаЛиста);
КонецЕсли;
Ну и в конце процедуры "СформироватьМакет" тоже добавим несколько строк.
///+++
_ДокументРезультат.Вывести(ДокументРезультат);
ДокументРезультат.Очистить();
ДокументРезультат = _ДокументРезультат;
///+++
КонецПроцедуры // СформироватьОтчет()
В результате, на табеле в 150 -200 сотрудников ускорение печати в 3 раза,
на табеле в 400 сотрудников - в 4 раза
Итог: мы провели расследование и добились результата, без профайлера, технологического журнала, трансляторов запроса и прочих изощренностей.
В качестве иллюстрации и для сравнения с типовой прилагаю модифицированную печатную форму, проверена на УПП 1.3.186.1 и ЗУП КОРП 2.5.175.1.