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

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

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

В этой статье мы подробно разберем, как работает механизм виртуальных таблиц «под капотом», проанализируем влияние отборов на скорость выполнения запроса и выясним, какие приемы позволяют ускорить получение данных в десятки раз.

Механика работы виртуальных таблиц и SQL-сервера

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

Рассмотрим два сценария:

  1. Без отбора в параметрах: Если параметры виртуальной таблицы пусты, SQL-сервер может попытаться рассчитать итоги по абсолютно всем записям регистра (или по всем актуальным итогам). Только после того как огромный массив данных будет подготовлен, система начнет «отсекать» лишнее через условие ЛЕВОЕ СОЕДИНЕНИЕ ... ПО .... Это приводит к колоссальным затратам памяти и времени.
  2. С отбором в параметрах: Когда мы передаем условия в круглых скобках виртуальной таблицы, платформа транслирует эти условия непосредственно во вложенный запрос. SQL-оптимизатор получает возможность использовать существующие индексы физических таблиц итогов, выбирая только те записи, которые нам действительно нужны.

Проанализируем практический пример: в некоторых случаях отсутствие условий в параметрах замедляет выполнение запроса в 60 и более раз. Это происходит потому, что вместо точечного поиска по индексу сервер выполняет полное сканирование (Table Scan или Index Scan) таблиц с миллионами записей.

Оптимизация связи по нескольким полям: использование кортежей

Часто требуется связать данные по нескольким измерениям одновременно, например, по номенклатуре и заказу. Рассмотрим распространенную ошибку, которую совершают разработчики при попытке оптимизации.

Плохое решение (разрозненные условия):


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

В данном случае система выберет все остатки по всем товарам из вашей таблицы и все остатки по всем заказам. В результат попадут «лишние» данные: остатки товара А по заказу Б, даже если в вашей исходной временной таблице была только пара Товар А + Заказ А. Это не только замедляет запрос, но и может привести к логическим ошибкам при расчетах.

Правильное решение (кортежное сравнение):

Для максимально точной фильтрации следует использовать сравнение списков значений (кортежей). Разберем, как это выглядит в коде:


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

Этот синтаксис заставляет SQL-сервер использовать составные индексы регистра наиболее эффективным образом, выбирая только строго определенные комбинации измерений.

Индексация временных таблиц: когда она необходима?

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

Посмотрим на ситуацию со стороны SQL-сервера. Чтобы выполнить условие IN (SELECT...), серверу нужно сопоставить данные. Если поле во временной таблице не проиндексировано, серверу придется сканировать временную таблицу столько раз, сколько записей он проверяет в основной таблице. Индексация полей связи во временной таблице позволяет использовать Nested Loops или более быстрые алгоритмы соединения.

Пример правильной подготовки временной таблицы:


ВЫБРАТЬ
    Заказ,
    Номенклатура,
    Склад
ПОМЕСТИТЬ вт_Фильтр
ИЗ
    Документ.ЗаказНаПроизводство.Товары КАК ЗаказТовары
ГДЕ
    Ссылка = &Ссылка
ИНДЕКСИРОВАТЬ ПО
    Номенклатура,
    Заказ,
    Склад
;

Почему вынос виртуальной таблицы в отдельную временную таблицу иногда замедляет работу?

Существует распространенный совет: «Никогда не соединяйте виртуальные таблицы напрямую, сначала выгрузите их во временные». Однако на практике это не всегда дает прирост скорости. Рассмотрим причины:

  1. Накладные расходы на TempDB: Создание каждой временной таблицы — это запись на диск в базу tempdb. Если данных мало (десятки или сотни строк), время на создание таблицы и запись в неё может превысить время самого расчета остатков.
  2. Потеря контекста для оптимизатора: Современные версии SQL-сервера и платформы 1С умеют «прокидывать» условия из левой таблицы в правую (виртуальную) даже без явного указания параметров, если запрос не слишком сложен. Принудительное разделение на разные временные таблицы разрывает эту логическую связь.

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

Массивы против временных таблиц в параметрах

Проанализируем еще одну особенность производительности. Иногда передача списка номенклатуры через массив (как параметр запроса) работает быстрее, чем использование В (ВЫБРАТЬ Номенклатура ИЗ вт_Номенклатура).

Итоговые рекомендации по оптимизации

Подведем итог нашему исследованию и сформулируем правила эффективного использования виртуальных таблиц:

  1. Всегда дублируйте ключевые фильтры в параметрах виртуальной таблицы. Если вы связываете по номенклатуре — добавьте отбор по номенклатуре в скобки Остатки(...) или Обороты(...).
  2. Используйте кортежи (Измерение1, Измерение2) В (...) для фильтрации по нескольким полям. Это предотвращает выборку лишних данных.
  3. Индексируйте поля связи во временных таблицах, которые используются как источник для фильтров в виртуальных таблицах.
  4. Избегайте избыточных вложений. Если вы уже вынесли данные во временную таблицу, старайтесь соединять её с физическими таблицами или другими проиндексированными ВТ, не создавая «матрешку» из условий В (ВЫБРАТЬ...).
  5. Для виртуальной таблицы ОстаткиИОбороты параметры фильтрации являются критически важными, так как эта таблица является самой «тяжелой» для расчета платформой.

Соблюдение этих правил позволит вам писать запросы, которые работают стабильно быстро даже при значительном росте объема данных в информационной базе.

← На главную