Почему СКД меняет логику запроса и как бороться с агрессивной оптимизацией временных таблиц?

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

Разработчики 1С часто сталкиваются с ситуацией, когда идеально отлаженный запрос в консоли выдает правильные данные, но стоит перенести его в Систему компоновки данных (СКД), как результат становится непредсказуемым. Проблема кроется в "избыточном интеллекте" компоновщика макета, который пытается оптимизировать запрос, удаляя из него всё, что он считает лишним. Разберем подробно, почему так происходит и как защитить свои данные от "грязных ручонок" оптимизатора СКД.

Механизм оптимизации: почему СКД лезет во временные таблицы?

Проанализируем работу КомпоновщикаМакетаКомпоновкиДанных. Его основная задача — подготовить максимально эффективный SQL-запрос для СУБД. Для этого система анализирует не только итоговую выборку, но и всю цепочку временных таблиц. Если СКД "видит", что поле, участвующее в группировке (СГРУППИРОВАТЬ ПО) во временной таблице, в дальнейшем не выводится в отчет, не используется в отборах, связях или группировках настроек, она исключает его из текста запроса.

Рассмотрим ситуацию: вы создаете временную таблицу, чтобы получить максимальное значение цены для каждого товара. Вы группируете данные по Номенклатура и вычисляете МАКСИМУМ(Цена). Если в итоговом отчете вы решили вывести только общую максимальную цену по складу, не указывая номенклатуру в группировках отчета, СКД может решить, что группировка по товару во временной таблице избыточна. Она удалит поле Номенклатура из секции СГРУППИРОВАТЬ ПО, и вы получите максимум по всей таблице цен вместо ожидаемого результата. Это и есть та самая ошибка оптимизации, способная испортить итоговые цифры.

Главное заблуждение: галочка «Автозаполнение»

Многие программисты свято верят, что снятие флага Автозаполнение в конструкторе схемы компоновки делает запрос "неприкосновенным". Выясним причину, почему это не так. Автозаполнение влияет исключительно на автоматическое формирование списка доступных полей, параметров и отборов в схеме. Однако механизм оптимизации (компоновщик макета) работает всегда, независимо от этой настройки. Он будет "резать" запрос, если посчитает, что логика формирования итогового набора данных не нарушится с его математической точки зрения.

Способ 1: Использование признака «Обязательное»

Самый надежный способ заставить СКД "видеть" поле и не выбрасывать его из промежуточных итогов — это установка признака Обязательное в настройках полей набора данных. Рассмотрим, как это работает:

  1. Перейдем в закладку Наборы данных схемы компоновки.
  2. Найдем поле, которое участвует в "исчезающей" группировке.
  3. В колонке Обязательное установим флаг.

Установка этого флага гарантирует, что поле будет присутствовать в запросе всегда, даже если пользователь не выбрал его для отображения в отчете. Это принудительно сохраняет структуру временных таблиц, в которых задействовано данное поле.

Способ 2: Настройка ролей полей

Если поле является ключевым для группировки, важно правильно указать его роль. В некоторых случаях СКД может игнорировать группировку, если не понимает иерархию или смысл поля. Разберем по шагам настройку ролей:

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

Способ 3: Рефакторинг запроса (разделение агрегатов)

Если в одном пакете запроса используется слишком много агрегатных функций (МАКСИМУМ, СУММА, КОЛИЧЕСТВО) вместе со сложными соединениями, оптимизатор СКД чаще совершает ошибки. Посмотрим на рекомендации опытных разработчиков: сложные расчеты лучше разносить по разным временным таблицам. Сначала выводим все необходимые свойства во временную таблицу, а в следующем пакете применяем к ним группировку и расчет агрегатов.

Пример структуры защищенного запроса:


// Пакет 1: Собираем "сырые" данные
ВЫБРАТЬ
    Продажи.Номенклатура КАК Товар,
    Продажи.СуммаОборот КАК Сумма
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи;

// Пакет 2: Агрегируем данные (здесь важно следить за группировкой)
ВЫБРАТЬ
    ВТ_Данные.Товар КАК Товар,
    СУММА(ВТ_Данные.Сумма) КАК ИтогоСумма
ПОМЕСТИТЬ ВТ_Итоги
ИЗ
    ВТ_Данные КАК ВТ_Данные
СГРУППИРОВАТЬ ПО
    ВТ_Данные.Товар;

Способ 4: Использование фигурных скобок для «обмана» оптимизатора

Существует еще один прием, позволяющий удержать поле в запросе — использование его внутри расширения языка запросов СКД (фигурных скобок). Если поле используется в условии, которое всегда истинно, компоновщик не сможет его удалить. Например:

ГДЕ {МоеВажноеПоле = МоеВажноеПоле}

Или включение поля в фиктивное соединение внутри фигурных скобок. Однако помните, что это скорее "хак", чем системное решение. Приоритетным методом остается установка флага Обязательное.

Как отловить проблему (Отладка макета)

Выясним причину, почему такие ошибки крайне сложно обнаружить. В консоли запросов всё работает правильно, так как там исполняется "чистый" текст запроса. Ошибка проявляется только на этапе генерации макета. Чтобы увидеть реальный текст, который СКД отправляет на SQL-сервер, проанализируем следующий код для отладки:


КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновкиДанных, ДанныеРасшифровки);

// Теперь в МакетКомпоновки.НаборыДанных можно найти реальные тексты запросов
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
    Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
        Сообщить(НаборДанных.Запрос); // Вот он, "оптимизированный" текст
    КонецЕсли;
КонецЦикла;

Проанализировав вывод этого кода, вы сразу увидите, какие части СГРУППИРОВАТЬ ПО были выброшены и какие временные таблицы подверглись упрощению. Это позволит вам точно определить "виновное" поле и применить к нему настройку Обязательное.

Подведем итог: Поведение СКД — это не баг в чистом виде, а следствие алгоритма повышения производительности. Чтобы ваши отчеты всегда показывали верные данные, не полагайтесь на то, что СКД оставит запрос неизменным. Всегда явно указывайте обязательные поля и контролируйте роли, особенно в сложных отчетах со множеством временных таблиц и агрегатных функций.

← На главную