В процессе разработки и доработки конфигураций 1С разработчики часто используют цепочки обращений к реквизитам через точку. Например, конструкции вида Заказ.Договор.Владелец.ИНН выглядят лаконично, однако при массовых проверках или проведении документов они способны существенно снизить производительность системы и сжигать значительную часть времени выполнения алгоритма.
Разберем подробнее, почему возникают задержки при таких обращениях и какими способами можно эффективно оптимизировать код.
Проанализируем механику работы платформы 1С при разыменовании ссылок в коде BSL:
Заказ.Договор), платформа не читает только одно нужное поле из СУБД. Она загружает в память весь объект целиком — со всеми его шапочными реквизитами и табличными частями. Если в цепочке используется несколько точек подряд (Заказ.Договор.Владелец.ИНН), платформа последовательно выполнит считывание нескольких полных объектов из базы данных.Владелец или Контрагент), платформа на уровне SQL-запроса формирует неявные левые соединения (LEFT JOIN) со всеми возможными таблицами метаданных, входящими в данный составной тип. Это создаёт высокую нагрузку на СУБД.Самый простой и быстрый способ оптимизировать обращение к отдельным реквизитам без переписывания глобальной логики на запросы — использовать функции общего модуля ОбщегоНазначения из БСП.
Эти функции внутри выполняют точечный оптимизированный запрос к базе данных и считывают только указанные поля, не загружая шапку и табличные части объекта целиком.
Посмотрим на основные функции БСП для получения реквизитов:
ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита) — позволяет быстро получить значение одного реквизита.ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, Реквизиты) — считывает массив или структуру реквизитов за одно обращение.ОбщегоНазначения.ЗначенияРеквизитовОбъектов(МассивСсылок, ИменаРеквизитов) — выполняет выборку по массиву однотипных или разнотипных ссылок.Рассмотрим пример замены кода. Вместо прямого обращения через точку:
// Неоптимальный вариант: считываются целиком Заказ и Договор
ИННКонтрагента = Заказ.Договор.Владелец.ИНН;
Используем поэтапное точечное получение реквизитов с помощью БСП:
Договор = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Заказ, "Договор");
Владелец = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Договор, "Владелец");
ИННКонтрагента = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Владелец, "ИНН");
Если в рамках одного алгоритма или проверки требуется неоднократно обращаться к реквизитам документа и связанных с ним справочников, наиболее эффективный подход — сформировать единую структуру данных в начале процедуры.
Рассмотрим порядок действий по шагам:
СтруктураШапкиДокумента) или соответствие.Пример реализации предварительного получения данных через запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Договор КАК Договор,
| Заказ.Договор.Владелец КАК Контрагент,
| Заказ.Договор.Владелец.ИНН КАК ИНН
|ИЗ
| Документ.ЗаказПокупателя КАК Заказ
|ГДЕ
| Заказ.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаЗаказ);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
// Все необходимые данные получены за 1 обращение к СУБД
ДоговорОбъекта = Выборка.Договор;
ИННКонтрагента = Выборка.ИНН;
КонецЕсли;
Если обращение к реквизиту происходит внутри запроса, но поля имеют составной тип (например, реквизит Владелец может быть как физическим, так и юридическим лицом), необходимо явно указывать тип объекта.
Рассмотрим, как конструкция ВЫРАЗИТЬ исключает лишние соединения SQL:
ВЫРАЗИТЬ(Заказ.Договор.Владелец КАК Справочник.Контрагенты).ИНН
Использование ВЫРАЗИТЬ указывает платформе обращаться только к одной конкретной таблице базы данных (в данном примере — Справочник.Контрагенты), благодаря чему из итогового SQL-запроса исключаются все остальные неиспользуемые соединения.
При попытке закэшировать данные через сервисные функции повторного использования (кэширующие функции 1С) необходимо учитывать ограничение платформы:
ДокументОбъект и т.д.) в параметры функций повторного использования.Таким образом, для разовых или уникальных документов оптимальным решением остаётся точечное получение реквизитов через ОбщегоНазначения.ЗначенияРеквизитовОбъекта или объединение проверок в один пакетный запрос.