Разыменование составных ссылок через точку в запросах 1С: откуда берутся лишние JOIN

18.08.26

База данных - HighLoad оптимизация

Практический разбор SQL-трансляции и способа ограничить число неявных соединений. В конкретном тесте: 3,8 с до изменения и 0,5 с после ограничения типа через «ВЫРАЗИТЬ». Структурный результат однозначен: шесть соединений с таблицами документов превратились в одно.

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

Количество этих соединений определяется составом типа. Если в поле разрешено хранить ссылки на шесть видов документов, при получении реквизита через точку в SQL формируются соединения с шестью таблицами документов. Сам факт появления этих JOIN не зависит от объема данных; отдельно оценивается их стоимость в конкретном плане выполнения. Ниже — исходный запрос, фактическая SQL-трансляция и результат после явного ограничения типа.

Сам прием с «ВЫРАЗИТЬ» не новый и описан в рекомендациях 1С. Здесь интерес представляет именно фактическая SQL-трансляция и практический замер. Рекомендация 1С:ИТС о разыменовании составных ссылочных полей

 

1. Что скрывается за составным типом

В рассматриваемом примере у документа «Заказ поставщику» есть реквизит «ДокументОснование». Его тип включает ссылки на несколько видов документов: заказ клиента, заказ на перемещение, приобретение товаров и другие документы.

Для прикладного разработчика это выглядит как одно поле:

ЗаказПоставщику.ДокументОснование

На уровне таблицы базы данных значение поля составного ссылочного типа представлено служебными составляющими, которые позволяют определить тип значения и конкретный объект. Пока запрос получает только саму ссылку, обращаться к таблице связанного объекта не требуется. Выражение вида «ДокументОснование.Номер» требует получить реквизит уже из таблицы связанного документа.

Если ссылочный тип составной и конкретный тип заранее не ограничен, при разыменовании платформа формирует соединения с таблицами всех ссылочных типов, входящих в состав этого поля. Именно это происходит в рассматриваемом запросе.

 

2. Исходный запрос

Нужно получить документ-основание заказа поставщику и номер этого основания:

ВЫБРАТЬ
    ЗаказПоставщику.ДокументОснование КАК ДокументОснование,
    ЗаказПоставщику.ДокументОснование.Номер КАК ДокументОснованиеНомер
ИЗ
    Документ.ЗаказПоставщику КАК ЗаказПоставщику
ГДЕ
    ЗаказПоставщику.Дата >= &Дата

В тексте запроса нет сложных вычислений. Ключевое место — обращение:

ЗаказПоставщику.ДокументОснование.Номер

В конкретной задаче номер был нужен только тогда, когда основание — «Документ.ЗаказКлиента». Для остальных типов значение номера не использовалось. Исходный запрос этого ограничения не содержал, поэтому при SQL-трансляции платформа учла все шесть допустимых типов и сформировала соединения со всеми шестью таблицами документов.

Это важная оговорка: дальнейшее изменение — не механическая замена синтаксиса «точки» на «ВЫРАЗИТЬ». Мы уточняем запрос в соответствии с реальным условием задачи.

 

3. Что получилось в SQL

В тестовой конфигурации в состав реквизита «ДокументОснование» входило шесть видов документов. При прямом обращении к «ДокументОснование.Номер» платформа сформировала шесть LEFT OUTER JOIN — по одному для каждого допустимого типа — и выражение CASE, выбирающее номер из таблицы фактического типа основания.

Ниже — SQL, полученный через используемую мной консоль запросов. Часть служебных имен в выводе заменена на имена реквизитов 1С, при этом физические имена таблиц и некоторые служебные поля СУБД сохранены.

Рис. 1. SQL до изменения: шесть LEFT OUTER JOIN и CASE для выбора номера

На скриншоте видно:

  • шесть соединений с физическими таблицами документов (_Document329, _Document324, _Document323, _Document322, _Document321 и _Document331);
  • CASE, который выбирает поле _Number из нужной таблицы в зависимости от типа ссылки;
  • дополнительные служебные условия платформы. Их конкретный вид зависит от конфигурации и настроек информационной базы.

Шесть JOIN в данном SQL — прямое следствие разыменования составной ссылки без ограничения типа. Их наличие само по себе не определяет время выполнения: фактическая стоимость зависит от выбранного плана, объема данных, индексов и статистики СУБД. В прикладной задаче требуется только один тип, поэтому это ограничение передаем платформе явно.

 

4. Ограничиваем тип через «ВЫРАЗИТЬ»

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

ВЫБРАТЬ
    ЗаказПоставщику.ДокументОснование КАК ДокументОснование,
    ВЫРАЗИТЬ(
        ЗаказПоставщику.ДокументОснование
        КАК Документ.ЗаказКлиента
    ).Номер КАК ДокументОснованиеНомер
ИЗ
    Документ.ЗаказПоставщику КАК ЗаказПоставщику
ГДЕ
    ЗаказПоставщику.Дата >= &Дата

После явного ограничения типа SQL содержит одно соединение с таблицей «ЗаказКлиента» вместо шести соединений со всеми допустимыми типами.

Рис. 2. SQL после «ВЫРАЗИТЬ»: одно соединение с таблицей нужного документа

На втором скриншоте остается один LEFT OUTER JOIN с _Document321. CASE для выбора номера из шести таблиц исчезает.

«ВЫРАЗИТЬ» не является отбором строк. Если в «ДокументОснование» хранится ссылка другого типа, выражение вернет NULL для реквизита «Номер», но сама строка останется в результате. Если строки других типов нужно исключить, дополнительно используется оператор «ССЫЛКА».

 

5. Что показал тест

Условия, в которых был получен результат:

 

Параметр Значение
Версия платформы 1С:Предприятие 8.3 (8.3.27.1859)
СУБД MS SQL Server 2019
Всего записей в таблице документов 136 907
Период выборки 3 года
Состояние кэша Кэш прогрет
Типов в «ДокументОснование» 6

 

В зафиксированном сравнении на этой базе исходная реализация выполнялась за 3,8 секунды, после ограничения типа — за 0,5 секунды.

 

Показатель До изменения После изменения
Присоединяемых таблиц документов 6 1
Время выполнения 3,8 с 0,5 с
Разница по времени — 3,3 с
Отношение времени — 7,6 раза

 

Цифру 7,6 нельзя переносить на другие запросы как «типичное ускорение от ВЫРАЗИТЬ»: это результат одного замера на одной базе. Гарантированным результатом в рассматриваемом запросе является изменение структуры SQL: шесть соединений вместо одного.

Есть и еще один принципиальный момент: вариант с «ВЫРАЗИТЬ» корректен только потому, что по условиям этой задачи номер требуется для «Документ.ЗаказКлиента», а для других типов ожидается NULL. При оптимизации нужно сохранять не текстовую эквивалентность исходной реализации, а требуемый прикладной результат.

 

6. Как выбрать конструкцию

У «ССЫЛКА» и «ВЫРАЗИТЬ» разные задачи. Конструкция определяется требуемым результатом: сохранить строки других типов или отфильтровать их.

6.1. Только «ВЫРАЗИТЬ»

Нужно получить реквизит одного конкретного типа, но строки с другими типами должны остаться в результате:

ВЫБРАТЬ
    ЗаказПоставщику.Ссылка,
    ЗаказПоставщику.ДокументОснование,
    ВЫРАЗИТЬ(
        ЗаказПоставщику.ДокументОснование
        КАК Документ.ЗаказКлиента
    ).Номер КАК НомерЗаказаКлиента
ИЗ
    Документ.ЗаказПоставщику КАК ЗаказПоставщику

Для оснований других типов «НомерЗаказаКлиента» будет NULL.

6.2. Только «ССЫЛКА»

Нужно оставить только строки определенного типа, но реквизиты связанного объекта не требуются:

ВЫБРАТЬ
    ЗаказПоставщику.Ссылка,
    ЗаказПоставщику.ДокументОснование
ИЗ
    Документ.ЗаказПоставщику КАК ЗаказПоставщику
ГДЕ
    ЗаказПоставщику.ДокументОснование
        ССЫЛКА Документ.ЗаказКлиента

6.3. «ССЫЛКА» и «ВЫРАЗИТЬ»

Нужно и отобрать конкретный тип, и получить его реквизит:

ВЫБРАТЬ
    ЗаказПоставщику.Ссылка,
    ВЫРАЗИТЬ(
        ЗаказПоставщику.ДокументОснование
        КАК Документ.ЗаказКлиента
    ).Номер КАК НомерЗаказаКлиента
ИЗ
    Документ.ЗаказПоставщику КАК ЗаказПоставщику
ГДЕ
    ЗаказПоставщику.ДокументОснование
        ССЫЛКА Документ.ЗаказКлиента

«ССЫЛКА» здесь отвечает за отбор строк, а «ВЫРАЗИТЬ» — за получение реквизита из конкретного типа.

6.4. Нужно обработать несколько типов

Если реквизит нужен для нескольких типов, их можно перечислить явно:

ВЫБРАТЬ
    ЗаказПоставщику.Ссылка,
    ВЫБОР
        КОГДА ЗаказПоставщику.ДокументОснование
                ССЫЛКА Документ.ЗаказКлиента
            ТОГДА ВЫРАЗИТЬ(
                ЗаказПоставщику.ДокументОснование
                КАК Документ.ЗаказКлиента
            ).Номер
        КОГДА ЗаказПоставщику.ДокументОснование
                ССЫЛКА Документ.ЗаказНаПеремещение
            ТОГДА ВЫРАЗИТЬ(
                ЗаказПоставщику.ДокументОснование
                КАК Документ.ЗаказНаПеремещение
            ).Номер
        ИНАЧЕ NULL
    КОНЕЦ КАК НомерОснования
ИЗ
    Документ.ЗаказПоставщику КАК ЗаказПоставщику

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

 

7. Как найти такую проблему в существующем запросе

Проверять нужно следующие признаки:

  • после добавления одного поля вида «Ссылка.Номер» или «Ссылка.Наименование» запрос заметно замедлился;
  • в сгенерированном SQL появилась серия LEFT JOIN к однотипным таблицам и большой CASE;
  • в фактическом плане есть таблицы, которые не нужны по смыслу конкретной задачи;
  • разыменовываемое поле имеет широкий составной или определяемый тип.

Порядок проверки простой: посмотреть SQL, определить реально нужные типы, ограничить их через «ВЫРАЗИТЬ», затем сравнить фактический план и время выполнения. Отдельно нужно проверить, что результат по пустым ссылкам и значениям других типов соответствует бизнес-логике.

 

8. Когда ничего переписывать не нужно

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

Поэтому правило здесь не «убрать все точки», а «понимать SQL, который формирует платформа». Сначала смотрим SQL и фактический план, затем меняем запрос там, где лишние соединения не требуются прикладной логикой.

Широкий состав реквизита, при котором конкретный механизм использует один-два типа из десятков, — отдельный архитектурный сигнал. Изменение типа реквизита в рабочей системе является самостоятельной задачей; для локальной оптимизации запроса достаточно явно ограничить те типы, реквизиты которых действительно нужны.

 

Практический чек-лист

  • Какой тип у поля: конкретный или составной?
  • Какие типы реально нужны в этой задаче?
  • Нужно сохранить строки других типов или отфильтровать их?
  • Что изменилось в SQL после «ВЫРАЗИТЬ»?
  • Что показывает фактический план и время выполнения?
  • Сохранился ли требуемый результат для пустых ссылок и других типов?

 

Заключение

Проблема не в самом разыменовании через точку, а в разыменовании составной ссылки без явного ограничения типа. В рассмотренном примере шесть допустимых типов «ДокументОснование» дали шесть LEFT OUTER JOIN и CASE для выбора номера. После ограничения типа через «ВЫРАЗИТЬ» в SQL осталось одно соединение — с таблицей того документа, который действительно требовался по условиям задачи.

Результат 3,8 с против 0,5 с относится к конкретному тесту и не является универсальным коэффициентом ускорения. Структурный результат однозначен: шесть соединений были заменены одним. Практический вывод: если прикладная логика заранее определяет конкретный тип составной ссылки, этот тип нужно явно сообщить платформе. «ССЫЛКА» используется для отбора по типу, «ВЫРАЗИТЬ» — для получения реквизитов конкретного типа.

Вступайте в нашу телеграмм-группу Инфостарт

1С запросы 1С оптимизация запросов 1С производительность 1С разыменование через точку составные ссылки ВЫРАЗИТЬ SQL-трансляция 1С JOIN язык запросов 1С

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Инструментарий разработчика Роли и права Запросы СКД Разработчик Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3 и 8.5: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 руб.

02.09.2020    285508    1606    423    

1220

Инструментарий разработчика Запросы Разработчик 1С:Предприятие 8 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

QueryConsole1C — расширение, включающее консоль запросов с поддержкой исполняемых представлений — аналогов виртуальных таблиц, основанных на методах программного интерфейса ЗУП. Оно позволяет выполнять запросы с учётом встроенной бизнес-логики, отлаживать алгоритмы получения данных и автоматически генерировать код на встроенном языке 1С.

1 стартмани

16.05.2025    13646    168    zup_dev    32    

87

Запросы Разработчик 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    24489    XilDen    40    

117

HighLoad оптимизация Разработчик 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Встал вопрос: как быстро удалить строки из ТЗ? Рассмотрел пять вариантов реализации этой задачи. Сравнил их друг с другом на разных объёмах данных с разным процентом удаляемых строк. Также сравнил с выгрузкой с отбором по структуре.

09.01.2024    48928    doom2good    50    

80

HighLoad оптимизация Системный администратор Разработчик Бесплатно (free)

При переводе типовой конфигурации 1C ERP/УТ/КА на PostgreSQL придется вложить ресурсы в доработку и оптимизацию запросов. Расскажем, на что обратить внимание при потерях производительности и какие инструменты/подходы помогут расследовать проблемы после перехода.

20.11.2023    25593    ivanov660    7    

85

HighLoad оптимизация Бесплатно (free)

Казалось бы, КОРП-системы должны быть устойчивы, быстры и надёжны. Но, работая в рамках РКЛ, мы видим немного другую картину. Об основных болевых точках КОРП-систем и подходах к их решению пойдет речь в статье.

15.11.2023    15015    a.doroshkevich    23    

78

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    29448    skovpin_sa    15    

109
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. SerVer1C 1146 19.08.26 09:23 Сейчас в теме
На заре входа в 1С про это первым делом говорят.
2. booksfill 19.08.26 10:33 Сейчас в теме
1. Какой-то крайне странный запрос у вас получился на скриншоте с тремя одинаковыми полями Т1.ДокументОснование, вместо чего-то типа
    ЗаказПоставщику._Fld123_TYPE AS ДокументОснование_TYPE,
    ЗаказПоставщику._Fld123_RTRF AS ДокументОснование_RTRF,
    ЗаказПоставщику._Fld123_RRREF AS ДокументОснование_RRREF,

ИИ ошибся?

2. Вы точно уверены, что этот ликбез не описан уже 100500 раз, в т.ч. в официальной документации?
Просто наберите "Разыменование ссылочных полей составного типа в языке запросов" - вы сильно удивитесь.

3. А вы знаете как иногда интересно скорость запроса реагирует на Выразить в условиях явного соединения по полю составного типа и почему все равно так делать не надо? Вот про что-то подобное хотя бы написали.
Подсказка: ИИ и про это знает, но вы можете это все обернуть в замеры, поиграться.

Или рассмотрите как на запросе сказываются поля составного типа с примитивными типами, или типами любая ссылка. Тоже описано, но хоть не так явно.

Или хотя бы рассмотрите примеры, когда поле составного типа выбирается без всякой точки. И что, например, получим когда проделываем это трюк в СКД, например, с регистратором.

Словом, раз уж решили заняться ликбезом, не стесняйтесь насиловать ИИ.
3. markbraer 128 19.08.26 15:27 Сейчас в теме
(2) По первому пункту: в статье прямо указано, что на скриншоте показан не «сырой» SQL из профайлера, а текст SQL из консоли запросов в режиме анализа планов запросов. После преобразований и подстановки имен метаданных он выглядит именно так, поэтому три разных служебных составляющих составной ссылки визуально отображаются как Т1.ДокументОснование.

То есть речь не о том, что платформа реально сформировала три одинаковых физических поля. Это представление SQL после обработки консолью для удобства анализа. В исходном SQL на уровне БД это, разумеется, разные служебные поля составной ссылки.
5. booksfill 19.08.26 18:14 Сейчас в теме
(3)
для удобства анализа

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

А вообще жду п.3.
Там много не такого уж очевидного и иногда требующего постараться для воспроизведения ситуации.
Я бы напряг Copilot, пущай он пишет тестовые примеры и статистику на SQL Server убивает/искажает.
Но у меня к нему доступа нет. Да и времени играться, к сожалению, не хватает.
6. markbraer 128 19.08.26 22:34 Сейчас в теме
(5) Я все пример моделирую на реальной базе. Это занимает определенное время. ИИ тут не нужен
4. markbraer 128 19.08.26 15:30 Сейчас в теме
2) Да, конечно, этот механизм давно описан. Более того, в начале статьи я именно это и написал: «Сам прием с ВЫРАЗИТЬ не новый и описан в рекомендациях 1С», там же дана ссылка на соответствующую статью ИТС. Цель материала не в том, чтобы представить известный прием как открытие, а показать на конкретном запросе фактическую SQL-трансляцию до и после изменения и замер на конкретной версии платформы и СУБД.
3) Это будет тема отдельного разбора
Для отправки сообщения требуется регистрация/авторизация