Каждый разработчик 1С рано или поздно сталкивается с ситуацией: написан сложный пакетный запрос, он протестирован в обычной консоли запросов и выдает идеальный результат. Но стоит перенести этот же текст в схему компоновки данных (СКД) и запустить отчет, как данные исчезают, итоги ломаются, а детальная аналитика (например, субконто в отчетах по бухгалтерии) просто отказывается выводиться.
Давайте разберем по шагам, почему так происходит, как работает внутренний механизм оптимизации СКД и каким образом заставить систему компоновки выдавать те же данные, что и консоль запросов.
Основная ошибка начинающих разработчиков заключается в представлении о СКД как о простом визуализаторе таблиц. На самом деле Система компоновки данных — это мощный интеллектуальный генератор макета. СКД никогда не отправляет ваш запрос в СУБД в исходном ("сыром") виде.
Когда пользователь нажимает кнопку "Сформировать", СКД анализирует текущие настройки отчета (выбранные поля, установленные группировки, отборы, условное оформление) и на их основе динамически перестраивает исходный текст запроса. Это делается ради оптимизации производительности: зачем СУБД выбирать из базы лишние гигабайты данных, если пользователь вывел в отчет всего две колонки?
Однако эта оптимизация часто приводит к побочным эффектам. Рассмотрим подробнее основные механизмы СКД, которые могут исказить логику вашего запроса:
ЛЕВОЕ СОЕДИНЕНИЕ, но в пользовательских настройках установлен жесткий отбор по полю из правой (присоединяемой) таблицы, СКД автоматически преобразует соединение во ВНУТРЕННЕЕ. В результате все строки из левой таблицы, для которых не нашлось соответствий, просто исчезнут из отчета.В контексте обсуждения на форуме мы столкнулись с классическим примером: в отчете по 1С:Бухгалтерии (БП 3.0) в оборотно-сальдовой ведомости не выводилась аналитика счета (субконто), хотя в консоли запросов она заполнялась корректно. Выясним, как решить эту проблему.
Если СКД "выбрасывает" из итогового запроса поле аналитики, потому что считает его неиспользуемым на определенном этапе компоновки макета, мы должны явно указать платформе, что это поле критически важно для логики расчета и его нельзя удалять ни при каких обстоятельствах.
Сделать это можно с помощью настройки ролей полей в наборе данных схемы компоновки. Проанализируем пошагово, как решить эту задачу:
ОсновнаяСхемаКомпоновкиДанных) в конфигураторе.Установка свойства "Обязательное" сообщает оптимизатору СКД: "Это поле должно присутствовать в результирующем запросе к СУБД всегда, даже если пользователь не выбрал его в настройках отчета, не использует в группировках и не наложил по нему отбор". Это гарантирует сохранение структуры выборки и правильность расчета итогов.
Чтобы не гадать на кофейной гуще и точно понять, как именно СКД изменяет ваш исходный код, необходимо проанализировать итоговый сгенерированный запрос. Обычная консоль запросов здесь не поможет. Рассмотрим два эффективных способа отладки.
Для детального анализа используйте обработку "Консоль системы компоновки данных" (ее можно скачать на официальном портале ИТС). В отличие от обычной консоли, она позволяет загрузить схему компоновки, применить к ней любые пользовательские настройки и увидеть сформированный xml-макет компоновки, а также реальный текст SQL-запроса, отправляемый на сервер базы данных.
Мы можем перехватить итоговый текст запроса программно прямо в процессе компоновки результата отчета. Для этого откроем модуль объекта нашего отчета и найдем (или создадим) предопределенную процедуру ПриКомпоновкеРезультата. Напишем следующий код:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Нам понадобятся установленные пользователем настройки
НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
// Создаем компоновщик макета, который и преобразует схему под настройки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);
// Проанализируем полученный макет.
// Если у нас один набор данных - запрос, мы можем получить его текст:
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
ТекстРеальногоЗапроса = НаборДанных.Запрос;
// Установите точку останова на следующей строке и посмотрите значение ТекстРеальногоЗапроса в табло
ЗаписьЖурналаРегистрации("РеальныйЗапросСКД", УровеньЖурналаРегистрации.Информация,,, ТекстРеальногоЗапроса);
КонецЕсли;
КонецЦикла;
// Далее выполняем стандартный вывод отчета с использованием полученного макета
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Запустите этот отчет в режиме "1С:Предприятие" под отладкой, установите точку останова внутри цикла на переменной ТекстРеальногоЗапроса. Откройте значение этой переменной через вычисление выражений (Shift+F9) — вы увидите тот самый реальный запрос с учетом всех оптимизаций. Сравните его с исходным запросом из схемы, и вы сразу поймете, какое именно поле или соединение "вырезала" система компоновки данных.
Подобный системный подход к отладке СКД позволяет быстро локализовать проблему расхождения данных и решить её за считанные минуты простым изменением ролей полей в конфигураторе.