Нужно ли индексировать временную таблицу, если выборка из нее используется как условие в виртуальной таблице 1С?

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

Анализ исходного запроса и суть проблемы

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


ВЫБРАТЬ
    СправочникОбъекты.Поле1 КАК Поле1
ПОМЕСТИТЬ ВТ_ПараметрОтбор
ИЗ
    Справочник.Объекты КАК СправочникОбъекты
;

ВЫБРАТЬ
    Обороты.ПолеИзмерение КАК ПолеИзмерение,
    Обороты.РесурсОборот КАК РесурсОборот
ИЗ
    РегистрНакопления.ДвиженияОбъектов.Обороты(
        ,
        ,
        ,
        ПолеИзмерение В
            (ВЫБРАТЬ
                ВТ_ПараметрОтбор.Поле1
            ИЗ
                ВТ_ПараметрОтбор КАК ВТ_ПараметрОтбор)
    ) КАК Обороты

Возникает практический вопрос: требуется ли индексировать поле Поле1 во временной таблице ВТ_ПараметрОтбор для обеспечения максимальной производительности?

Стандарты разработки 1С и механика СУБД

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

Рассмотрим, почему это критично на уровне СУБД (например, MS SQL Server или PostgreSQL):

  1. Преобразование подзапроса в соединение: Оптимизатор запросов СУБД при трансляции выражения В (ВЫБРАТЬ ...) преобразует подзапрос в операцию полусоединения (Semi-Join) или внутреннего соединения (Inner Join). По этой причине выборка из временной таблицы сопоставляется с физическими индексами таблиц баз данных.
  2. Использование индексов СУБД: Наличие индекса по полю временной таблицы позволяет оптимизатору СУБД применить точечный поиск по индексу (Index Seek) вместо полного сканирования таблицы (Table Scan).
  3. Сбор статистики: При создании индекса во временной таблице платформа 1С и СУБД автоматически генерируют статистику по индексируемому полю. На основе этой статистики оптимизатор точнее оценивает количество строк (cardinality estimation) и корректно выбирает алгоритм соединения (например, Nested Loops вместо ресурсоемкого Hash Join).

Ограничения платформы при подзапросах в параметрах виртуальных таблиц

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

  1. В подзапросе должна присутствовать только одна таблица, без явных или неявных соединений.
  2. Запрещено обращение к реквизитам «через точку» (неявные соединения).
  3. При обращении к табличной части документа запрещено привлекать реквизиты шапки.
  4. Условия внутри подзапроса не должны провоцировать наложение ограничений прав доступа на уровне записей (RLS).

Альтернативные способы оптимизации и практические рекомендации

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

  1. Передача массива значений через параметр: Если объем фильтруемых данных невелик (до нескольких сотен элементов), эффективнее отказаться от создания временной таблицы и передать готовый массив прямо в параметр запроса: Запрос.УстановитьПараметр("МассивОбъектов", МассивЗначений); В тексте запроса условие принимает вид ПолеИзмерение В (&МассивОбъектов). Это исключает накладные расходы на создание структуры временной таблицы, вставку данных и её удаление.
  2. Явное соединение с физической таблицей регистра: Для работы с большими объемами данных или в сложных запросах надежнее выполнять явное внутреннее соединение с предварительно проиндексированной временной таблицей по физической таблице регистра:
    
    ВЫБРАТЬ
        СправочникОбъекты.Поле1 КАК Поле1
    ПОМЕСТИТЬ ВТ_ПараметрОтбор
    ИЗ
        Справочник.Объекты КАК СправочникОбъекты
    ИНДЕКСИРОВАТЬ ПО
        Поле1
    ;
    
    ВЫБРАТЬ
        Движения.ПолеИзмерение КАК ПолеИзмерение,
        Движения.Ресурс КАК Ресурс
    ИЗ
        ВТ_ПараметрОтбор КАК ВТ_ПараметрОтбор
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ДвиженияОбъектов КАК Движения
            ПО ВТ_ПараметрОтбор.Поле1 = Движения.ПолеИзмерение
    
    В данном сценарии индексирование поля Поле1 во временной таблице является обязательным условием для эффективного сопоставления записей.
  3. Предварительная выборка во временную таблицу: Если виртуальная таблица с подзапросом в параметрах работает медленно из-за сложности плана, можно предварительно выбрать необходимые данные из виртуальной таблицы во временную таблицу без жестких фильтров, а затем соединить две временные таблицы в отдельном пакете запроса.

Таким образом, при использовании выборки из временной таблицы в качестве подзапроса В (ВЫБРАТЬ ...) индексировать поле временной таблицы нужно, если объем данных превышает несколько десятков строк или требуется гарантировать стабильный и оптимальный план выполнения запроса СУБД.

← На главную