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