Как убрать соединения и обращения к временным таблицам в СКД, если поле не используется?

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

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

Проанализируем эту ситуацию. Если поле не выбрано пользователем, мы не хотим, чтобы платформа тратила ресурсы на вычисление связанных с ним временных таблиц или выполнение лишних левых соединений, а также на расчет виртуальных таблиц остатков. Разберем по шагам, как можно решить эту задачу, начиная от рабочих «костылей» и заканчивая правильными встроенными механизмами платформы 1С.

Вариант 1: Использование параметров (обходной путь)

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

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


ВЫБРАТЬ
    Таблица1.Ссылка,
    Таблица2.ДопПоле
ИЗ
    Справочник.Номенклатура КАК Таблица1
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Свойства КАК Таблица2
    ПО (ВЫБОР 
            КОГДА &ВыводитьРезультатСдопСвязью ТОГДА Таблица1.Ссылка = Таблица2.Объект
            ИНАЧЕ ИСТИНА 
        КОНЕЦ)

Недостатки метода: Это крайне некрасивое решение с точки зрения оптимизатора СУБД. Такое условие ВЫБОР КОГДА ... ИНАЧЕ ИСТИНА сводит на нет использование индексов, что приведет к сильному замедлению запроса. Кроме того, нам придется программно устанавливать этот параметр перед формированием отчета, анализируя выбранные пользователем поля, либо перекладывать ответственность на пользователя, заставляя его вручную ставить галочки в параметрах.

Вариант 2: Программное формирование запроса или Функциональные опции

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

Недостатки метода: Поддержка такого отчета становится сложной. Если подобных полей несколько, количество комбинаций текстов запроса будет расти в геометрической прогрессии. Нам нужен более изящный, нативный выход из ситуации.

Вариант 3: Использование расширения языка запросов СКД (Правильное решение)

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

1. Необязательные соединения

Если левое соединение необходимо только для того, чтобы вытянуть одно конкретное поле (например, цену из регистра сведений), мы можем заключить всё соединение в фигурные скобки. Посмотрим на пример:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Товар,
    Цены.Цена КАК Цена
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    {ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены КАК Цены 
    ПО Номенклатура.Ссылка = Цены.Номенклатура}

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

2. Необязательные поля во временных таблицах

Если мы формируем временную таблицу (ВТ) в пакетном запросе, мы можем указать необязательные поля внутри неё. Разберем конструкцию:


ВЫБРАТЬ
    Документ.Ссылка,
    {Документ.Менеджер КАК Менеджер}
ПОМЕСТИТЬ ВТ_Документы
ИЗ
    Документ.ЗаказКлиента КАК Документ

Оптимизатор СКД работает очень умно. Если в пакете формируется временная таблица, но данные из неё в конечном итоге нигде не используются (пользователь снял все флажки с полей, приходящих из этой ВТ), то платформа вообще пропустит выполнение этой части пакета. Временная таблица не будет создана, что сэкономит ресурсы сервера.

Вариант 4: Несколько «Наборов данных» вместо левых соединений

Проанализируем архитектуру сложного запроса. Если отчет собирает данные из совершенно разных сущностей (например, продажи за период и текущие остатки на складах), хорошей практикой является использование нескольких наборов данных вместо сборки огромного пакетного запроса.

  1. Создайте первый набор данных: НаборДанных1 (Документы).
  2. Создайте второй набор данных: НаборДанных2 (Остатки).
  3. Перейдите на вкладку Связи наборов данных и укажите, по какому полю они связываются (например, Номенклатура).

Логика работы СКД в этом случае идеальна: если пользователь не выведет в отчет ни одного поля из набора «Остатки» и не наложит на них условия, СКД даже не будет выполнять запрос ко второму набору данных. Соединение (которое происходит программно на уровне сервера 1С при компоновке) будет пропущено.

Вариант 5: Отключение расчета остатков для невыбранных полей

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

Чтобы управлять этим поведением и не считать остатки по полю, если оно не используется, выполним следующие шаги:

  1. Снимите галочку Автозаполнение в конструкторе запроса СКД.
  2. Вручную опишите параметры виртуальной таблицы с использованием расширения СКД.

Посмотрим на пример правильного оформления виртуальной таблицы:


ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.Склад КАК Склад,
    Остатки.КоличествоОстаток КАК Количество
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(
        {(&Период)}, 
        {Номенклатура.*, (Склад).* КАК СкладПользователя}
    ) КАК Остатки

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

← На главную