Как избежать обращения к реквизитам через точку в запросе 1С и оптимизировать производительность

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

При написании запросов в платформе 1С:Предприятие часто используется обращение к реквизитам ссылочных полей через точку (например, Документ.Договор.Владелец или Продажи.Договор.Организация). Такое разыменование полей удобно при написании кода, однако на уровне СУБД оно превращается в неявные левые соединения. При работе с большими объемами данных или реквизитами составного типа это может привести к существенному падению производительности. Разберем, как устроена работа обращений через точку, какие риски они несут и какими способами можно от них отказаться.

Суть проблемы: как СУБД обрабатывает обращения через точку

Когда в секции ВЫБРАТЬ или в других частях запроса выполняется обращение к реквизиту связанной таблицы через точку, платформа 1С автоматически подставляет неявное левое соединение (LEFT JOIN) с соответствующей физической таблицей базы данных.

Рассмотрим, как количество «точек» влияет на сложность итогового SQL-запроса:

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

Особая опасность: реквизиты составного типа

Наиболее тяжелые последствия возникают при обращении через точку к реквизитам составного типа. Если поле может содержать ссылки на несколько различных типов объектов (например, реквизит Регистратор или измерение СчетФактура, содержащее ссылки на 10–15 видов документов), платформа не знает заранее, какой именно объект хранится в конкретной строке.

В этом случае на уровне SQL-запроса платформа 1С вынуждена выполнять соединение со всеми физическими таблицами, входящими в этот составной тип, а выбор конкретного значения происходит с помощью конструкции CASE WHEN. В результате вместо одного легкого соединения генерируются десятки LEFT JOIN, что критически замедляет выполнение запроса (особенно в динамических списках и высоконагруженных отчетах).

Способ 1. Использование функции ВЫРАЗИТЬ для составных типов

Если необходимо обратиться к реквизиту поля составного типа, но в конкретном контексте заранее известен точный тип объекта, следует применить функцию ВЫРАЗИТЬ(). Она сообщает платформе, к какой именно таблице нужно выполнить соединение, исключая все остальные варианты.

Посмотрим на пример ограничения составного типа СчетФактура в регистре накопления:


ВЫБРАТЬ
    ВЫРАЗИТЬ(Регистр.СчетФактура КАК Документ.ПоступлениеТоваровУслуг).НомерВходящегоДокумента КАК НомерВходДок
ИЗ
    РегистрНакопления.НДСЗаписиКнигиПокупок КАК Регистр

Если поле составного типа может содержать 2–3 конкретных вида документов или справочников, вместо множественных неявных соединений эффективнее использовать ветвление с проверкой типа с помощью ключевого слова ССЫЛКА:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Источник.Заказ ССЫЛКА Документ.ЗаказПокупателя 
            ТОГДА ВЫРАЗИТЬ(Источник.Заказ КАК Документ.ЗаказПокупателя).Номер
        КОГДА Источник.Заказ ССЫЛКА Документ.ЗаказПоставщику 
            ТОГДА ВЫРАЗИТЬ(Источник.Заказ КАК Документ.ЗаказПоставщику).Номер
        ИНАЧЕ ""
    КОНЕЦ КАК НомерЗаказа
ИЗ
    Документ.РеализацияТоваровУслуг КАК Источник

Такой подход позволяет платформе построить ветвление на уровне SQL только для указанных видов объектов, избегая соединения с остальными таблицами составного типа.

Способ 2. Явное левое соединение (ЛЕВОЕ СОЕДИНЕНИЕ)

Самый прозрачный и управляемый способ избежать неопределенности — отказаться от разыменования полей в пользу явного написания секции ЛЕВОЕ СОЕДИНЕНИЕ.

Проанализируем ситуацию, когда необходимо получить контрагента из договора документа:


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

Преимущества явного соединения очевидны:

Скрытые подводные камни обращений через точку

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

  1. Искажение логики при отборах в секции ГДЕ: Разыменование поля в секции ВЫБРАТЬ создает LEFT JOIN. Однако если то же поле с точкой используется в условии ГДЕ (например, ГДЕ Реализация.Договор.ВидДоговора = &Вид), СУБД фактически превращает такое соединение во внутреннее (INNER JOIN). Если в документе не заполнен договор, вся строка целиком выпадет из итоговой выборки.
  2. Влияние RLS (ограничения доступа на уровне записей): При обращении к реквизиту через точку платформа автоматически подтягивает условия RLS, настроенные для целевой таблицы. Если RLS целевого справочника содержит сложные подзапросы, даже простое обращение к полю через точку может кардинально замедлить запрос.
  3. Падение производительности виртуальных таблиц: Использование полей через точку в параметрах виртуальных таблиц (в отборах регистров) заставляет платформу производить соединения до расчета агрегатов и применения индексов самой виртуальной таблицы, что приводит к сплошному сканированию данных (Table Scan).

Архитектурное решение: использование временных таблиц

Для сложных и объёмных запросов с большим количеством связей наилучшим решением является двухэтапная обработка данных с помощью временных таблиц:

  1. Сначала выбираются уникальные ссылки и первичные ключи во временную таблицу и обязательно индексируются по полям связи с помощью конструкции ИНДЕКСИРОВАТЬ ПО.
  2. Затем выполняется явное соединение основной таблицы с подготовленной временной таблицей.

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


// Шаг 1: Подготовка уникальных ключей связывания
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Реализация.ДоговорКонтрагента КАК Договор
ПОМЕСТИТЬ ВТ_УникальныеДоговоры
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Дата МЕЖДУ &ДатаНач И &ДатаКон
ИНДЕКСИРОВАТЬ ПО
    Договор
;

// Шаг 2: Получение реквизитов и явное соединение
ВЫБРАТЬ
    Реализация.Ссылка КАК Документ,
    Договоры.Владелец КАК Контрагент
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_УникальныеДоговоры КАК ВТ_Договоры
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК Договоры
        ПО ВТ_Договоры.Договор = Договоры.Ссылка
    ПО Реализация.ДоговорКонтрагента = ВТ_Договоры.Договор

Такой подход гарантирует оптимизатору СУБД точную статистику, исключает повторные тяжелые соединения с физическими таблицами и обеспечивает максимальную скорость выполнения запроса.

← На главную