При разработке отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда данные выбираются мгновенно, но при попытке вывести результат в табличный документ программа «зависает» на несколько минут. Особенно остро эта проблема проявляется при использовании программного вывода, когда метод ПВ.Вывести(ПК, Истина) (где ПВ — ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений, а ПК — ПроцессорКомпоновкиДанных) начинает выполняться аномально долго. Давайте детально разберем, что происходит в «черном ящике» СКД в этот момент и как мы можем ускорить процесс.
Для начала проанализируем, почему именно на этапе Вывести() происходит основная задержка. В СКД процесс получения данных разделен на несколько этапов. Сначала компоновщик макета готовит схему, затем процессор компоновки выбирает данные из источников. Однако финальные вычисления — расчет итогов, вычисление ресурсов, проверка правил условного оформления и получение представлений ссылок — происходят именно в момент итеративного обхода данных процессором вывода. Если в отчете 10 000 строк, и для каждой строки выполняются сложные вычисления, общее время ожидания будет складываться из этих микро-задержек.
Одной из наиболее частых причин медленной работы является использование набора данных типа «Объект» (обычно это ТаблицаЗначений) совместно с набором данных типа «Запрос». Рассмотрим ситуацию, когда ТаблицаЗначений выступает ведомым набором в левом соединении. Проанализируем механизм: СКД не может выполнить соединение на уровне SQL-сервера, так как часть данных находится в оперативной памяти (ТЗ), а часть — в базе данных.
В этом случае часто возникает проблема N+1. СКД может начать выполнять отдельный запрос к базе данных для каждой строки из вашей таблицы значений, чтобы получить связанные данные. Если строк 10 000, мы получаем 10 000 микро-запросов к БД.
Что мы можем сделать:
Тип значения. Если тип не определен, процессор компоновки тратит время на определение типа каждой ячейки.Выясним еще одну важную деталь: расчет ресурсов происходит именно во время вывода. Если в поле Выражение на вкладке «Ресурсы» используется сложная формула или обращение к функции общего модуля, это значительно замедляет отчет. Рассмотрим пример функции, которая вызывается для каждой группировки:
// В выражении ресурса СКД:
МойОбщийМодуль.РассчитатьСложныйКоэффициент(СуммаОстаток, Количество)
Если такая функция не кэширует результаты и выполняет внутри себя дополнительные запросы или сложные циклы, отчет будет «тупить». Проанализируем решение: максимально перенесем расчеты в текст основного запроса. SQL справляется с арифметикой гораздо быстрее, чем программный код 1С при выводе каждой строки.
Посмотрим на рекомендации опытных разработчиков: иногда замена ссылок на строковые представления (превращение ссылки в текст еще на уровне запроса) дает прирост скорости. Хотя СКД автоматически получает представления для полей типа СправочникСсылка или ДокументСсылка, делает она это через неявные соединения с таблицами этих объектов.
Если в отчете много ссылочных полей, попробуем в запросе явно получать Поле.Представление и выводить его как отдельную строку. Это исключит необходимость обращения к метаданным в процессе компоновки результата.
Рассмотрим ситуацию с оформлением. Если в отчете настроено 10–15 правил условного оформления (например, «раскрасить строку в красный, если остаток меньше нуля и склад основной»), СКД анализирует каждое условие для каждой ячейки.
Чтобы ускорить этот процесс, выполним следующие шаги:
ЭтоКритическийОстаток.Истина/Ложь. Это гораздо быстрее, чем заставлять процессор вывода вычислять сложные логические выражения.Когда мы работаем с внешним набором данных (ТЗ), критически важно обеспечить строгую типизацию. Если в описании полей набора данных «Объект» поле имеет составной тип или тип вовсе не указан, СКД обрабатывает его крайне неэффективно. Проанализируем настройки: пройдемся по каждой колонке набора данных и выставим конкретные типы (Число, Строка, СправочникСсылка...). Это избавит ПВ.Вывести() от лишней работы по динамическому определению метаданных.
Проверим настройки на вкладке «Наборы данных» в колонке «Роли». Неправильно расставленные роли (особенно для периодов и родительских элементов в иерархии) заставляют процессор вывода строить сложные деревья зависимостей в памяти. Если в отчете используется иерархия, убедимся, что:
Выясним, как работает «Автозаполнение» в запросе. При включенной галочке СКД анализирует все таблицы, участвующие в запросе, и подтягивает массу служебной информации. Для сложных, тормозящих отчетов хорошей практикой считается снятие этой галочки и ручное указание только необходимых полей на вкладке «Наборы данных». Это облегчает структуру данных, которую обрабатывает процессор компоновки.
Подводя итог, можно сказать: если ПВ.Вывести() работает долго, проблема почти всегда кроется не в объеме данных, а в сложности их обработки «на лету». Оптимизация запроса, типизация ТЗ и упрощение ресурсов — три кита, на которых держится быстрый отчет СКД.