Почему запрос работает в консоли 1С, но не выводит данные в СКД? Разбираемся с оптимизацией компоновки

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

Каждый разработчик 1С рано или поздно сталкивается с ситуацией: написан сложный пакетный запрос, он протестирован в обычной консоли запросов и выдает идеальный результат. Но стоит перенести этот же текст в схему компоновки данных (СКД) и запустить отчет, как данные исчезают, итоги ломаются, а детальная аналитика (например, субконто в отчетах по бухгалтерии) просто отказывается выводиться.

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

Выясняем причину: почему СКД переписывает наш запрос?

Основная ошибка начинающих разработчиков заключается в представлении о СКД как о простом визуализаторе таблиц. На самом деле Система компоновки данных — это мощный интеллектуальный генератор макета. СКД никогда не отправляет ваш запрос в СУБД в исходном ("сыром") виде.

Когда пользователь нажимает кнопку "Сформировать", СКД анализирует текущие настройки отчета (выбранные поля, установленные группировки, отборы, условное оформление) и на их основе динамически перестраивает исходный текст запроса. Это делается ради оптимизации производительности: зачем СУБД выбирать из базы лишние гигабайты данных, если пользователь вывел в отчет всего две колонки?

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

  1. Исключение "неиспользуемых" полей. Если поле присутствует в выборке запроса, но не добавлено пользователем в список выбранных полей, группировок или отборов, СКД полностью удаляет его из итогового SQL-запроса. Если это поле участвовало в группировках временных таблиц или влияло на детальность (зернистость) выборки, его удаление полностью меняет логику и итоги.
  2. Трансформация типов соединений. Если у вас в запросе настроено ЛЕВОЕ СОЕДИНЕНИЕ, но в пользовательских настройках установлен жесткий отбор по полю из правой (присоединяемой) таблицы, СКД автоматически преобразует соединение во ВНУТРЕННЕЕ. В результате все строки из левой таблицы, для которых не нашлось соответствий, просто исчезнут из отчета.
  3. Оптимизация виртуальных таблиц. СКД пытается наложить пользовательские отборы как можно раньше. Вместо того чтобы фильтровать уже готовый результат соединения, она внедряет отборы непосредственно в параметры виртуальных таблиц (например, в параметры среза последних или оборотов регистров), что может разрушить сложную логику связей.

В контексте обсуждения на форуме мы столкнулись с классическим примером: в отчете по 1С:Бухгалтерии (БП 3.0) в оборотно-сальдовой ведомости не выводилась аналитика счета (субконто), хотя в консоли запросов она заполнялась корректно. Выясним, как решить эту проблему.

Решение проблемы: управление ролями полей и флаг "Обязательное"

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

Сделать это можно с помощью настройки ролей полей в наборе данных схемы компоновки. Проанализируем пошагово, как решить эту задачу:

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

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

Как увидеть реальный запрос, который СКД отправляет в СУБД?

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

Способ 1. Использование специализированной консоли СКД

Для детального анализа используйте обработку "Консоль системы компоновки данных" (ее можно скачать на официальном портале ИТС). В отличие от обычной консоли, она позволяет загрузить схему компоновки, применить к ней любые пользовательские настройки и увидеть сформированный xml-макет компоновки, а также реальный текст SQL-запроса, отправляемый на сервер базы данных.

Способ 2. Программный перехват запроса в отладчике

Мы можем перехватить итоговый текст запроса программно прямо в процессе компоновки результата отчета. Для этого откроем модуль объекта нашего отчета и найдем (или создадим) предопределенную процедуру ПриКомпоновкеРезультата. Напишем следующий код:


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

Запустите этот отчет в режиме "1С:Предприятие" под отладкой, установите точку останова внутри цикла на переменной ТекстРеальногоЗапроса. Откройте значение этой переменной через вычисление выражений (Shift+F9) — вы увидите тот самый реальный запрос с учетом всех оптимизаций. Сравните его с исходным запросом из схемы, и вы сразу поймете, какое именно поле или соединение "вырезала" система компоновки данных.

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

← На главную