Как оптимизировать обращения к реквизитам объектов через точку в 1С?

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

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

Разберем подробнее, почему возникают задержки при таких обращениях и какими способами можно эффективно оптимизировать код.

Выясним причину: почему разыменование ссылок через точку работает медленно

Проанализируем механику работы платформы 1С при разыменовании ссылок в коде BSL:

  1. Считывание объекта целиком. Когда происходит обращение к реквизиту объекта через ссылку (например, Заказ.Договор), платформа не читает только одно нужное поле из СУБД. Она загружает в память весь объект целиком — со всеми его шапочными реквизитами и табличными частями. Если в цепочке используется несколько точек подряд (Заказ.Договор.Владелец.ИНН), платформа последовательно выполнит считывание нескольких полных объектов из базы данных.
  2. Избыточные соединения при составных типах. Если один из реквизитов в цепочке имеет составной тип данных (например, реквизит Владелец или Контрагент), платформа на уровне SQL-запроса формирует неявные левые соединения (LEFT JOIN) со всеми возможными таблицами метаданных, входящими в данный составной тип. Это создаёт высокую нагрузку на СУБД.
  3. Повторные вызовы на клиенте. Если аналогичные обращения выполняются на стороне клиента, каждое разыменование вызывает отдельный контекстный или неконтекстный серверный вызов, что приводит к задержкам передачи данных по сети.

Решение 1. Использование стандартных функций Библиотеки Стандартных Подсистем (БСП)

Самый простой и быстрый способ оптимизировать обращение к отдельным реквизитам без переписывания глобальной логики на запросы — использовать функции общего модуля ОбщегоНазначения из БСП.

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

Посмотрим на основные функции БСП для получения реквизитов:

  1. ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита) — позволяет быстро получить значение одного реквизита.
  2. ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, Реквизиты) — считывает массив или структуру реквизитов за одно обращение.
  3. ОбщегоНазначения.ЗначенияРеквизитовОбъектов(МассивСсылок, ИменаРеквизитов) — выполняет выборку по массиву однотипных или разнотипных ссылок.

Рассмотрим пример замены кода. Вместо прямого обращения через точку:


// Неоптимальный вариант: считываются целиком Заказ и Договор
ИННКонтрагента = Заказ.Договор.Владелец.ИНН;

Используем поэтапное точечное получение реквизитов с помощью БСП:


Договор = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Заказ, "Договор");
Владелец = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Договор, "Владелец");
ИННКонтрагента = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Владелец, "ИНН");

Решение 2. Предварительное кэширование и заполнение структуры шапки

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

Рассмотрим порядок действий по шагам:

  1. Перед началом проверок выполняем один пакетный запрос, который выбирает все необходимые данные по всем цепочкам связей за один раз.
  2. Сохраняем полученные значения в структуру (например, СтруктураШапкиДокумента) или соответствие.
  3. В дальнейших проверках и бизнес-логике обращаемся исключительно к свойствам этой структуры.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Заказ.Договор КАК Договор,
    |	Заказ.Договор.Владелец КАК Контрагент,
    |	Заказ.Договор.Владелец.ИНН КАК ИНН
    |ИЗ
    |	Документ.ЗаказПокупателя КАК Заказ
    |ГДЕ
    |	Заказ.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаЗаказ);
РезультатЗапроса = Запрос.Выполнить();

Если НЕ РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    
    // Все необходимые данные получены за 1 обращение к СУБД
    ДоговорОбъекта = Выборка.Договор;
    ИННКонтрагента = Выборка.ИНН;
КонецЕсли;

Решение 3. Оптимизация обращений к составным типам с помощью ВЫРАЗИТЬ

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

Рассмотрим, как конструкция ВЫРАЗИТЬ исключает лишние соединения SQL:

ВЫРАЗИТЬ(Заказ.Договор.Владелец КАК Справочник.Контрагенты).ИНН

Использование ВЫРАЗИТЬ указывает платформе обращаться только к одной конкретной таблице базы данных (в данном примере — Справочник.Контрагенты), благодаря чему из итогового SQL-запроса исключаются все остальные неиспользуемые соединения.

Особые нюансы использования повторно используемых модулей

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

Таким образом, для разовых или уникальных документов оптимальным решением остаётся точечное получение реквизитов через ОбщегоНазначения.ЗначенияРеквизитовОбъекта или объединение проверок в один пакетный запрос.

← На главную