Часто при разработке отчетов на базе Системы Компоновки Данных (СКД) возникает необходимость связать два набора данных: основной набор-объект (например, Таблицу Значений с заказами) и подчиненный набор-запрос (например, срез последних регистра сведений со статусами). Проанализируем ситуацию: в основной таблице может быть всего пара строк, а в регистре — сотни тысяч записей. Если связь настроена некорректно, отчет работает крайне медленно, поскольку фильтры на срез не накладываются должным образом или выполняются запросы в цикле.
Разберем по шагам, почему возникает эта проблема и как ее правильно решить, чтобы добиться оптимальной производительности.
Выясним причину падения производительности. Существуют серьезные ограничения платформы при связывании разных типов наборов:
В (&МассивПараметров) внутри параметров виртуальных таблиц (например, в срезе последних) часто приводит к неоптимальным планам запросов на сервере баз данных. Оптимизатору сложно применять индексы при поиске по большому массиву неупорядоченных ключей.NULL, а подчиненный набор не вернул данные.Рассмотрим первый вариант решения проблемы, если отказаться от использования двух наборов нельзя. Необходимо передавать параметр непосредственно в настройках связи наборов данных, а не в параметрах самого подчиненного набора. Передача списка (массива) позволит избежать выполнения запроса для каждой отдельной строки главного набора.
Однако, как было отмечено выше, при этом левое соединение может превратиться во внутреннее, отсекая строки из основного набора, для которых не найден статус. Обойдем эту проблему, переписав запрос подчиненного набора так, чтобы он сам выполнял левое соединение с нужной таблицей.
Посмотрим на пример кода для подчиненного набора-запроса:
ВЫБРАТЬ
уатЗаказГрузоотправителя.Ссылка КАК Заказ,
ЕСТЬNULL(СрезСтатусы.Статус, ЗНАЧЕНИЕ(Справочник.уатСтатусы_уэ.ПустаяСсылка)) КАК Статус
ИЗ
Документ.уатЗаказГрузоотправителя КАК уатЗаказГрузоотправителя
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.уатСтатусыГрузов_уэ.СрезПоследних(, Заказ В (&Заказ)) КАК СрезСтатусы
ПО (уатЗаказГрузоотправителя.Ссылка = СрезСтатусы.Заказ)
ГДЕ
уатЗаказГрузоотправителя.Ссылка В(&Заказ)
В данном запросе мы явно соединяем таблицу документа со срезом последних регистра сведений, накладывая условие В(&Заказ). Это гарантирует, что даже если в регистре нет записей, запрос вернет строку с пустой ссылкой статуса (благодаря функции ЕСТЬNULL), и СКД корректно обработает эти данные без потери строк главного набора.
Если есть возможность изменить архитектуру отчета, настоятельно рекомендуем использовать передачу временных таблиц. Это наиболее производительный подход, так как он переносит всю логику соединения на сторону СУБД, исключая построчную сшивку в СКД.
Запрос.МенеджерВременныхТаблиц из этого запроса.ПроцессорКомпоновкиДанных при его инициализации.ЛЕВЫМ СОЕДИНЕНИЕМ.В этом случае база данных выполнит соединение за один вызов максимально быстро.
Рассмотрим еще несколько практических советов по оптимизации, если вы все-таки используете связи наборов данных: