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