При разработке запросов в платформе 1С:Предприятие часто возникает вопрос: допустимо ли соединять физические таблицы информационной базы (например, справочники или документы) напрямую через конструкцию ЛЕВОЕ СОЕДИНЕНИЕ / ВНУТРЕННЕЕ СОЕДИНЕНИЕ, или же правильнее сначала поместить данные одной из таблиц во временную таблицу?
Разберем логику работы СУБД, оценим производительность каждого подхода и выясним, в каких ситуациях прямое соединение является оптимальным, а когда без временных таблиц не обойтись.
Прямое соединение двух и более физических таблиц — это абсолютно корректная и стандартная практика в языке запросов 1С. В подавляющем большинстве случаев (около 95–98%) именно такое написание запроса дает лучшую производительность, так как оптимизатор СУБД (MS SQL Server, PostgreSQL) самостоятельно строит наиболее эффективный план выполнения.
Рассмотрим пример стандартного прямого соединения справочника номенклатуры и документа:
ВЫБРАТЬ
РеализацияТоваров.Ссылка КАК Документ,
РеализацияТоваров.Контрагент КАК Контрагент,
Номенклатура.Наименование КАК Номенклатура
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваров
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
ПО РеализацияТоваров.Товары.Номенклатура = Номенклатура.Ссылка
В данном случае оптимизатор СУБД использует существующие первичные индексы таблиц и выбирает наилучший алгоритм соединения (например, Nested Loops или Hash Join). Создание временной таблицы для такой операции было бы избыточным и привело бы к лишним накладным расходам.
Проблемы с производительностью при прямом соединении возникают в следующих ситуациях:
Table Scan или Index Scan).ПО или ГДЕ (например, Документ.Контрагент.ОсновнойДоговор) платформа автоматически создает дополнительные внешние соединения, усложняя план запроса.ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ...), оптимизатор СУБД часто не может корректно оценить количество строк (cardinality), что ведет к выбору медленного алгоритма выполнения.Помещение данных из физической таблицы во временную перед основным соединением оправдано в следующих сценариях:
1. Повторное использование данных в пакетном запросе. Если данные из физической таблицы требуются в нескольких запросах одного пакета, предварительная выборка во временную таблицу сокращает количество обращений к дисковой подсистеме СУБД.
2. Соединение по неиндексированным реквизитам. При помещении данных во временную таблицу можно явно создать индекс по полям связи с помощью инструкции ИНДЕКСИРОВАТЬ ПО:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
Контрагенты.КодПоОКПО КАК ОКПО
ПОМЕСТИТЬ ВТ_Контрагенты
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
НЕ Контрагенты.ЭтоГруппа
ИНДЕКСИРОВАТЬ ПО
ОКПО
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Контрагенты.Контрагент КАК Контрагент,
ДругаяТаблица.Данные КАК Данные
ИЗ
ВТ_Контрагенты КАК ВТ_Контрагенты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВнешниеДанные КАК ДругаяТаблица
ПО ВТ_Контрагенты.ОКПО = ДругаяТаблица.ОКПО
3. Разделение сложных группировок и фильтрации. Если перед соединением данные необходимо предварительно сгруппировать, отфильтровать или агрегировать, рекомендуется вынести эти операции во временную таблицу, чтобы упростить итоговый запрос для оптимизатора СУБД.
Необходимо помнить, что временные таблицы создаются во временной служебной базе СУБД (TempDB в MS SQL Server или tempdb в PostgreSQL). Это связано с накладными расходами:
Проанализировав оба подхода, сформулируем практические правила:
Ссылка, первичные ключи) и выборка не требует сложной предварительной агрегации.ИНДЕКСИРОВАТЬ ПО, если связь выполняется по неиндексированным полям или исходные данные участвуют в нескольких запросах пакета.