Почему функция ПРЕДСТАВЛЕНИЕ() в запросах 1С может замедлять работу и как избежать лишних соединений SQL?

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

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

Суть проблемы: лишний LEFT JOIN на ровном месте

Рассмотрим стандартную ситуацию. У нас есть справочник Справочник1, в котором переопределена процедура ОбработкаПолученияПолейПредставления. Это делается для того, чтобы вместо стандартного наименования или кода платформа выводила в качестве представления значение определенного реквизита (или комбинацию полей).

Пример кода в модуле менеджера справочника:


Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    Поля.Добавить("Реквизит1");
КонецПроцедуры

Теперь проанализируем, как ведут себя разные варианты написания запроса для получения представления этого справочника. Посмотрим на два варианта, которые, казалось бы, должны работать идентично.

Вариант 1: Обращение через стандартное поле Представление


ВЫБРАТЬ
    Справочник1.Представление КАК Представление
ИЗ
    Справочник.Справочник1 КАК Справочник1

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


SELECT T1._Fld72 -- (где _Fld72 это наш Реквизит1)
FROM dbo._Reference71 T1

Вариант 2: Использование функции ПРЕДСТАВЛЕНИЕ(Ссылка)


ВЫБРАТЬ
    ПРЕДСТАВЛЕНИЕ(Справочник1.Ссылка) КАК Представление
ИЗ
    Справочник.Справочник1 КАК Справочник1

Здесь нас ждет сюрприз. Несмотря на то, что мы запрашиваем данные из той же самой таблицы, 1С транслирует запрос следующим образом:


SELECT T2._Fld72
FROM dbo._Reference71 T1
LEFT OUTER JOIN dbo._Reference71 T2
   ON T1._IDRRef = T2._IDRRef

Мы видим лишнее левое соединение таблицы самой с собой по первичному ключу. На справочнике в 10 000 элементов это не будет заметно, но если в таблице миллионы записей, такое соединение может значительно увеличить нагрузку на CPU и количество логических чтений в СУБД.

Почему платформа 1С строит запрос именно так?

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

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

Влияние на производительность и планы запроса

Проанализируем ситуацию с точки зрения СУБД. Несмотря на то, что соединение идет по первичному ключу (_IDRRef), который всегда проиндексирован, лишняя операция в плане запроса не проходит бесследно. Обычно в плане мы увидим Merge Join или Hash Match и два сканирования индекса (Index Scan).

Основные риски:

Рекомендации по оптимизации

Разберем по шагам, как избежать деградации производительности при работе с представлениями в больших таблицах.

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

Резюме: Знание того, как 1С преобразует высокоуровневые функции в SQL-код, позволяет избегать «детских» ошибок на больших объемах данных. Помните, что универсальность функции ПРЕДСТАВЛЕНИЕ() — это её слабое место с точки зрения производительности.

← На главную