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

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

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

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

Транзитивность условий: помогать ли оптимизатору?

Рассмотрим ситуацию, когда мы соединяем две таблицы (например, табличную часть документа и регистр сведений) и накладываем фильтр по ссылке на документ. Автор темы задает вопрос: будет ли запрос работать быстрее, если прописать условие &Ссылка для обеих таблиц?


ВЫБРАТЬ
    Товары.Номенклатура,
    ВТ.Статус
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК Товары
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.Статусы КАК ВТ
    ПО Товары.Ссылка = ВТ.Документ
ГДЕ
    Товары.Ссылка = &СсылкаНаМойДокумент
    И ВТ.Документ = &СсылкаНаМойДокумент // Нужно ли это условие?

Разберем механизм транзитивного замыкания. Современные СУБД (MS SQL Server, PostgreSQL) обладают мощными оптимизаторами, которые самостоятельно «пробрасывают» условия. Если в запросе указано A = B и A = X, оптимизатор автоматически понимает, что B = X. В простых запросах ручное дублирование не даст прироста производительности, так как план выполнения будет идентичным.

Однако существуют исключения, когда явное указание условий необходимо:

  1. Сложные вложенные запросы: Когда соединение происходит с подзапросом или виртуальной таблицей, оптимизатор может не «увидеть» возможность ранней фильтрации данных.
  2. Использование логического ИЛИ: Предикаты с ИЛИ часто ломают логику транзитивности, и оптимизатор может выбрать сканирование всей таблицы вместо поиска по индексу.
  3. Составные типы данных: Если поле соединения имеет составной тип, явное ограничение типа и значения помогает СУБД точнее оценить количество строк (Cardinality Estimation).

План выполнения запроса: декларация против алгоритма

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

Оптимизатор анализирует статистику распределения данных в таблицах. Если в таблице 10 строк, SQL-серверу проще прочитать их все (Scan). Если в таблице миллион строк, он будет искать конкретную запись через индекс (Seek). Именно поэтому на тестовых базах запросы могут летать, а на рабочих — «умирать».

Разбираем физические операторы соединения

Когда мы соединяем таблицы, СУБД выбирает один из трех основных алгоритмов. Рассмотрим их подробнее:

1. Nested Loops (Вложенные циклы)
Этот оператор часто критикуют, но для 1С он является основным и наиболее эффективным в большинстве случаев. Работает он просто: берется строка из одной таблицы и для нее ищется соответствие в другой. Это идеально, когда «внешняя» таблица мала (например, один документ), а во «внутренней» есть индекс по полю соединения.

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

3. Hash Join (Хэш-соединение)
Применяется, когда данных много, а подходящих индексов для Nested Loops или Merge нет. СУБД строит хэш-таблицу в оперативной памяти. Это ресурсоемкая операция, которая часто свидетельствует о неоптимальности индексов или отсутствии фильтров.

Загадка полей «Дата» и «Номер»

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


ВЫБРАТЬ 
    РТУ.Дата,
    РТУ.Номер
ИЗ 
    Документ.РеализацияТоваровУслуг КАК РТУ

Выясним причину. В 1С кластерный индекс (самый эффективный способ хранения данных) построен по полю Ссылка. Поля Дата и Номер входят в дополнительные индексы. Если мы просто выбираем эти поля без фильтра по ссылке, СУБД может решить, что выгоднее сделать Clustered Index Scan (полное сканирование основной таблицы), чтобы не прыгать между индексами. На больших базах это приводит к огромным затратам на чтение с диска.

Типы сканирования: Seek против Scan

При чтении планов запроса крайне важно различать эти два понятия:

Практические советы по оптимизации соединений

Проанализировав дискуссию и лучшие практики, выделим ключевые правила:

  1. Индексируйте Временные Таблицы: Если вы соединяете временную таблицу с физической, всегда создавайте индекс в ВТ по полям соединения. Это позволяет оптимизатору построить Nested Loops или Merge Join.
  2. Следите за типами данных: Неявное приведение типов (например, сравнение строки с числом или составного типа с конкретной ссылкой без ВЫРАЗИТЬ) убивает использование индексов.
  3. Условия в ПО против ГДЕ: Для внутреннего соединения разницы нет. Но для ЛЕВОЕ СОЕДИНЕНИЕ условия в ПО ограничивают присоединяемую таблицу, а в ГДЕ — весь итоговый результат, что может кардинально изменить план и результат.
  4. Обновляйте статистику: Даже идеально написанный запрос будет тормозить, если СУБД «думает», что в таблице 100 строк, хотя их там миллион. Регулярное регламентное обслуживание — залог стабильности планов.

Подводя итог: ручное дублирование условий в простых соединениях обычно избыточно, но понимание того, как SQL строит план, критически важно для работы с высоконагруженными системами. Используйте консоль запросов с просмотром плана выполнения, чтобы наглядно видеть разницу между Seek и Scan в ваших конкретных условиях.

← На главную