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