Как предотвратить автоматическое удаление полей и искажение логики запроса в СКД?

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

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

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

Суть проблемы: когда оптимизация становится ошибкой

Рассмотрим ситуацию, когда в запросе создается временная таблица для расчета нарастающего итога. Для этого нам необходимо соединить таблицу саму с собой по условию Период >= Период. Проанализируем пример исходного запроса, который должен подготовить данные:


ВЫБРАТЬ
    ДАТАВРЕМЯ(2019, 1, 1) КАК Период,
    "ФизЛицо" КАК ФизЛицо,
    "Подразделение" КАК Подразделение,
    10 КАК Результат
ПОМЕСТИТЬ ВТ_Начисления
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ ДАТАВРЕМЯ(2019, 2, 1), "ФизЛицо", "Подразделение", 10
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ ДАТАВРЕМЯ(2019, 3, 1), "ФизЛицо", "Подразделение", 10;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Начисления.Период,
    ВТ_Начисления.ФизЛицо,
    ВТ_Начисления.Подразделение,
    ВТ_Начисления.Результат,
    СУММА(ВТ_НачисленияСНачалаПериода.Результат) КАК СуммаСНачаПериода
ПОМЕСТИТЬ ВТ_НачисленияПериоды
ИЗ
    ВТ_Начисления КАК ВТ_Начисления
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Начисления КАК ВТ_НачисленияСНачалаПериода
    ПО ВТ_Начисления.Период >= ВТ_НачисленияСНачалаПериода.Период
    И ВТ_Начисления.ФизЛицо = ВТ_НачисленияСНачалаПериода.ФизЛицо
СГРУППИРОВАТЬ ПО
    ВТ_Начисления.Период,
    ВТ_Начисления.Результат,
    ВТ_Начисления.ФизЛицо,
    ВТ_Начисления.Подразделение;

Если в настройках компоновки (на вкладке «Выбранные поля») пользователь не укажет поле Период, СКД решит, что оно не нужно. Она исключит его из списка ВЫБРАТЬ и, что самое критичное, из секции СГРУППИРОВАТЬ ПО во временной таблице ВТ_НачисленияПериоды. В результате данные за разные месяцы «схлопнутся» в одну строку, и логика накопительного итога будет полностью разрушена. Вместо трех строк с результатами 10, 20 и 30 мы получим одну строку с некорректными данными.

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

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

  1. Откройте схему компоновки данных.
  2. Перейдите на закладку Наборы данных.
  3. В списке полей найдите то поле, которое СКД пытается «оптимизировать» (в нашем примере это Период).
  4. В колонке Обязательное установите флажок.

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

Способ 2: Принудительный вывод поля в итоговый запрос

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

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

Способ 3: Обертывание во вложенный запрос

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

Но будьте осторожны: вложенные запросы могут негативно сказаться на производительности, особенно при работе с большими объемами данных в СУБД. Рекомендуется использовать этот метод только в крайних случаях, когда пакетные временные таблицы по каким-то причинам не подходят.

Способ 4: Агрегация периода в последующих пакетах

Как предложил автор темы, проблему можно решить, изменив структуру самого запроса. Если нам нужен итог, но период мешает в конце, мы можем продолжать тащить Период через все временные таблицы, агрегируя его (например, используя МАКСИМУМ(Период) или КОЛИЧЕСТВО(Период)), и только в самом последнем пакете ВЫБРАТЬ «забыть» про него.

Посмотрим на пример измененного кода:


ВЫБРАТЬ
    Количество(ВТ_НачисленияПериоды.Период) КАК Индекс,
    ВТ_НачисленияПериоды.ФизЛицо,
    ВТ_НачисленияПериоды.Подразделение,
    СУММА(ВТ_НачисленияПериоды.Результат) КАК Результат,
    МАКСИМУМ(ВТ_НачисленияПериоды.СуммаСНачаПериода) КАК СуммаСНачаПериода
ПОМЕСТИТЬ ВТ_НачисленияОбщая
ИЗ
    ВТ_НачисленияПериоды КАК ВТ_НачисленияПериоды
СГРУППИРОВАТЬ ПО
    ВТ_НачисленияПериоды.ФизЛицо,
    ВТ_НачисленияПериоды.Подразделение;

Здесь мы используем Количество(ВТ_НачисленияПериоды.Период). Поскольку поле Период участвует в агрегатной функции внутри пакета, оптимизатор СКД с большой вероятностью оставит его в предыдущих временных таблицах, так как оно становится необходимым для расчета поля Индекс.

Способ 5: Отключение автозаполнения

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

Хотя это требует больше трудозатрат, это дает полный контроль над итоговым текстом запроса. СКД не сможет самовольно удалять поля из секции ВЫБРАТЬ, так как структура запроса теперь жестко определена вами.

Рекомендации по версиям платформы

Выясним причину, почему на разных версиях платформы (например, 8.3.12 и 8.3.15) один и тот же отчет может вести себя по-разному. Фирма «1С» постоянно совершенствует оптимизатор СКД. В новых версиях он становится более «агрессивным». Если в старой версии платформы СКД могла оставить поле «на всякий случай», то в новых версиях (8.3.15+) механизм Join Pruning (удаление неиспользуемых соединений) и очистка списков полей работают гораздо жестче. Поэтому при переходе на новые релизы платформы важно проверять сложные отчеты на предмет корректности работы накопительных итогов и сложных группировок во временных таблицах.

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

← На главную