При работе с реквизитами составного типа (например, Основание, который может ссылаться на любые документы в базе) часто возникает вопрос: как правильно и с максимальной производительностью наложить фильтр в запросе по конкретному документу-основанию. Разберем три распространенных варианта написания условий и проанализируем, как platforma 1С и СУБД транслируют их в реальные SQL-запросы.
Рассмотрим задачу: необходимо выбрать все документы ЗаказНаряд, у которых в реквизите Основание (составной тип данных) указан конкретный документ ЗаказПокупателя, переданный в параметр &Основание.
Вариант 1 (Явная проверка типа ССЫЛКА + равенство):
ВЫБРАТЬ
ЗаказНаряд.Ссылка КАК Ссылка
ИЗ
Документ.ЗаказНаряд КАК ЗаказНаряд
ГДЕ
ЗаказНаряд.Основание ССЫЛКА Документ.ЗаказПокупателя
И ЗаказНаряд.Основание = &Основание
Вариант 2 (Прямое равенство с параметром):
ВЫБРАТЬ
ЗаказНаряд.Ссылка КАК Ссылка
ИЗ
Документ.ЗаказНаряд КАК ЗаказНаряд
ГДЕ
ЗаказНаряд.Основание = &Основание
Вариант 3 (Использование ВЫРАЗИТЬ в секции ГДЕ):
ВЫБРАТЬ
ЗаказНаряд.Ссылка КАК Ссылка
ИЗ
Документ.ЗаказНаряд КАК ЗаказНаряд
ГДЕ
(ВЫРАЗИТЬ(ЗаказНаряд.Основание КАК Документ.ЗаказПокупателя)) = &Основание
Проанализируем поведение оптимизатора СУБД при выполнении каждого из трех вариантов запроса на реальной базе данных с проиндексированным полем Основание.
&Основание конкретной ссылки на документ платформа 1С автоматически определяет тип данных этого параметра. Поле составного типа в таблице СУБД состоит из трех колонок: типа (_TYPE), метаданных (_RTRef) и самого идентификатора (_RRRef). При прямом сравнении СУБД выполняет быстрый поиск по индексу (Index Seek), сразу проверяя все три составные части ключа. В плане выполнения СУБД это выглядит как 3 операции чтения.ЗаказНаряд.Основание ССЫЛКА Документ.ЗаказПокупателя генерирует дублирующую проверку типа на уровне SQL. СУБД выполняет абсолютно тот же поиск по индексу (Index Seek) и те же 3 операции чтения. Условие ССЫЛКА здесь избыточно, так как передаваемый параметр &Основание уже жестко определяет тип документа.ВЫРАЗИТЬ внутри секции ГДЕ транслируется платформой 1С в T-SQL конструкцию вида CASE WHEN ... THEN _RRRef END = @P2. Вычисление функции поверх индексируемой колонки делает данное условие неиндексируемым (non-SARGable). В результате СУБД теряет возможность использовать точечный поиск по индексу и переходит к сплошному сканированию индекса или таблицы (Index Scan), рассчитывая выражение CASE для каждой строки в таблице. Число чтений при этом возрастает с единиц до тысяч.Чтобы лучше понять причины такого поведения, разберем, как составные реквизиты физически хранятся в базе данных. Для каждого реквизита составного типа платформа 1С создает три колонки в соответствующей таблице базы данных:
_TYPE — тип данных (например, бинарный код, определяющий ссылку, строку, число и т. д.);_RTRef — уникальный идентификатор таблицы конкретного объекта метаданных;_RRRef — GUID (16 байт) конкретной ссылки.Когда мы пишем условие ЗаказНаряд.Основание = &Основание, платформа передает значение параметра раскладом по этим трем полям. В результате СУБД сразу выполняет точечную выборку по составному индексу по триаде полей (_TYPE, _RTRef, _RRRef).
Использование конструкции ВЫРАЗИТЬ категорически не рекомендуется в секциях ГДЕ и ПО при сравнении значений. Однако ВЫРАЗИТЬ выполняет важнейшую функцию в других случаях:
ЗаказНаряд.Основание.Дата, платформа 1С сделает неявные левые соединения (LEFT JOIN) со всеми таблицами документов, входящими в этот составной тип. Если типов десятки, запрос критически замедлится. Ограничить соединения поможет ВЫРАЗИТЬ:
ВЫБРАТЬ
ВЫРАЗИТЬ(ЗаказНаряд.Основание КАК Документ.ЗаказПокупателя).Дата КАК ДатаЗаказа
ИЗ
Документ.ЗаказНаряд КАК ЗаказНаряд
ВЫРАЗИТЬ прямо в секции ВЫБРАТЬ, чтобы типизировать колонку временной таблицы и избежать распространения неявных соединений на последующие запросы пакета.Выяснив причины работы оптимизатора СУБД, сформулируем правила работы с реквизитами составных типов:
Поле = &Параметр). Это самый чистый и быстрый код.ВЫРАЗИТЬ в секции ГДЕ, чтобы не провоцировать сплошной Index Scan на стороне СУБД.