Почему отчет СКД долго выводится на этапе ПВ.Вывести() и как это ускорить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда данные выбираются мгновенно, но при попытке вывести результат в табличный документ программа «зависает» на несколько минут. Особенно остро эта проблема проявляется при использовании программного вывода, когда метод ПВ.Вывести(ПК, Истина) (где ПВ — ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений, а ПК — ПроцессорКомпоновкиДанных) начинает выполняться аномально долго. Давайте детально разберем, что происходит в «черном ящике» СКД в этот момент и как мы можем ускорить процесс.

Разберем архитектуру процесса вывода

Для начала проанализируем, почему именно на этапе Вывести() происходит основная задержка. В СКД процесс получения данных разделен на несколько этапов. Сначала компоновщик макета готовит схему, затем процессор компоновки выбирает данные из источников. Однако финальные вычисления — расчет итогов, вычисление ресурсов, проверка правил условного оформления и получение представлений ссылок — происходят именно в момент итеративного обхода данных процессором вывода. Если в отчете 10 000 строк, и для каждой строки выполняются сложные вычисления, общее время ожидания будет складываться из этих микро-задержек.

Проблема соединения наборов данных «Запрос» и «Объект»

Одной из наиболее частых причин медленной работы является использование набора данных типа «Объект» (обычно это ТаблицаЗначений) совместно с набором данных типа «Запрос». Рассмотрим ситуацию, когда ТаблицаЗначений выступает ведомым набором в левом соединении. Проанализируем механизм: СКД не может выполнить соединение на уровне SQL-сервера, так как часть данных находится в оперативной памяти (ТЗ), а часть — в базе данных.

В этом случае часто возникает проблема N+1. СКД может начать выполнять отдельный запрос к базе данных для каждой строки из вашей таблицы значений, чтобы получить связанные данные. Если строк 10 000, мы получаем 10 000 микро-запросов к БД.

Что мы можем сделать:

  1. Постараемся максимально объединить данные до передачи их в СКД. Если есть возможность, лучше загрузить данные из ТЗ во временную таблицу внутри основного запроса.
  2. Если соединение неизбежно, обязательно проверим наличие индексов. В наборе данных «Объект» на вкладке «Наборы данных» нужно убедиться, что поля связи проиндексированы.
  3. Проверим типизацию. Для колонок таблицы значений в СКД необходимо явно указать Тип значения. Если тип не определен, процессор компоновки тратит время на определение типа каждой ячейки.

Оптимизация вычисляемых полей и ресурсов

Выясним еще одну важную деталь: расчет ресурсов происходит именно во время вывода. Если в поле Выражение на вкладке «Ресурсы» используется сложная формула или обращение к функции общего модуля, это значительно замедляет отчет. Рассмотрим пример функции, которая вызывается для каждой группировки:


// В выражении ресурса СКД:
МойОбщийМодуль.РассчитатьСложныйКоэффициент(СуммаОстаток, Количество)

Если такая функция не кэширует результаты и выполняет внутри себя дополнительные запросы или сложные циклы, отчет будет «тупить». Проанализируем решение: максимально перенесем расчеты в текст основного запроса. SQL справляется с арифметикой гораздо быстрее, чем программный код 1С при выводе каждой строки.

Влияние представлений ссылочных типов

Посмотрим на рекомендации опытных разработчиков: иногда замена ссылок на строковые представления (превращение ссылки в текст еще на уровне запроса) дает прирост скорости. Хотя СКД автоматически получает представления для полей типа СправочникСсылка или ДокументСсылка, делает она это через неявные соединения с таблицами этих объектов.

Если в отчете много ссылочных полей, попробуем в запросе явно получать Поле.Представление и выводить его как отдельную строку. Это исключит необходимость обращения к метаданным в процессе компоновки результата.

Условное оформление — невидимый потребитель ресурсов

Рассмотрим ситуацию с оформлением. Если в отчете настроено 10–15 правил условного оформления (например, «раскрасить строку в красный, если остаток меньше нуля и склад основной»), СКД анализирует каждое условие для каждой ячейки.

Чтобы ускорить этот процесс, выполним следующие шаги:

  1. Перенесем логику условий в запрос. Создадим в запросе булево поле, например, ЭтоКритическийОстаток.
  2. В правилах условного оформления будем проверять только это готовое поле Истина/Ложь. Это гораздо быстрее, чем заставлять процессор вывода вычислять сложные логические выражения.

Типизация полей в наборе данных «Объект»

Когда мы работаем с внешним набором данных (ТЗ), критически важно обеспечить строгую типизацию. Если в описании полей набора данных «Объект» поле имеет составной тип или тип вовсе не указан, СКД обрабатывает его крайне неэффективно. Проанализируем настройки: пройдемся по каждой колонке набора данных и выставим конкретные типы (Число, Строка, СправочникСсылка...). Это избавит ПВ.Вывести() от лишней работы по динамическому определению метаданных.

Роли полей и иерархия

Проверим настройки на вкладке «Наборы данных» в колонке «Роли». Неправильно расставленные роли (особенно для периодов и родительских элементов в иерархии) заставляют процессор вывода строить сложные деревья зависимостей в памяти. Если в отчете используется иерархия, убедимся, что:

Использование галочки «Автозаполнение»

Выясним, как работает «Автозаполнение» в запросе. При включенной галочке СКД анализирует все таблицы, участвующие в запросе, и подтягивает массу служебной информации. Для сложных, тормозящих отчетов хорошей практикой считается снятие этой галочки и ручное указание только необходимых полей на вкладке «Наборы данных». Это облегчает структуру данных, которую обрабатывает процессор компоновки.

Подводя итог, можно сказать: если ПВ.Вывести() работает долго, проблема почти всегда кроется не в объеме данных, а в сложности их обработки «на лету». Оптимизация запроса, типизация ТЗ и упрощение ресурсов — три кита, на которых держится быстрый отчет СКД.

← На главную