При разработке и оптимизации конфигураций на платформе 1С:Предприятие 8.3 в режиме тонкого клиента разработчики часто сталкиваются с вопросом выбора между объектным чтением (обращением через точку) и выборкой данных через запросы. Разберем детально, как устроена работа с данными в памяти, когда допустимо использовать обращение через точку, а когда это приводит к критическому падению производительности.
Рассмотрим две принципиально разные ситуации, которые часто ошибочно объединяют под общим понятием «обращение через точку»:
Объект): конструкция вида Специалист = Объект.Специалист; на сервере формы обращается к данным, которые уже находятся в оперативной памяти текущего сеанса. Платформа не выполняет дополнительных запросов к СУБД для чтения этого поля. Более того, чтение через запрос в данном случае вернет данные из базы, а не текущие несохраненные изменения пользователя.График = Объект.Специалист.ГрафикРаботы; приводит к тому, что платформа берет ссылку Объект.Специалист и считывает из базы данных весь объект справочника целиком в сеансовый кэш, чтобы получить одно значение.Посмотрим на наглядный пример в коде модуля формы:
&НаСервере
Процедура ОбработатьДанныеНаСервере()
// ВАРИАНТ 1: Допустимо и быстро.
// Значение реквизита берется напрямую из структуры данных формы в памяти.
ТекущийСпециалист = Объект.Специалист;
// ВАРИАНТ 2: Неоптимально (неявный запрос и считывание всего объекта).
// Происходит чтение всех реквизитов шапки справочника "Специалисты".
График = Объект.Специалист.ГрафикРаботы;
// ВАРИАНТ 3: Оптимально для получения реквизитов связанных объектов.
// Выбираются только необходимые поля без чтения объекта целиком.
График = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ТекущийСпециалист, "ГрафикРаботы");
КонецПроцедуры
Разберем основные сценарии и определим правила выбора подхода:
ОбщегоНазначения.ЗначениеРеквизитаОбъекта() или ОбщегоНазначения.ЗначенияРеквизитовОбъекта() (для нескольких полей).Объект.ИмяРеквизита является единственно верным решением.Проанализируем механику работы языка запросов 1С при обращении к полям через точку (например, ПланРабот.Специалист.ГрафикРаботы):
Платформа автоматически транслирует такие конструкции в инструкции LEFT OUTER JOIN (левое внешнее соединение) к таблице СУБД. Однако здесь присутствуют важные нюансы:
ВЫБРАТЬ, ГДЕ или УПОРЯДОЧИТЬ ПО неоднократно обращаться через точку к разным полям одной и той же ссылки, платформа может сформировать несколько одинаковых соединений с одной таблицей, усложняя план выполнения запроса. Явное левое соединение (ЛЕВОЕ СОЕДИНЕНИЕ) позволяет точно контролировать структуру запроса.CASE WHEN. Для исключения этой проблемы обязательно применяем оператор ВЫРАЗИТЬ.Посмотрим на пример правильного ограничения типа в запросе:
ВЫБРАТЬ
Заказ.Ссылка КАК Ссылка,
ВЫРАЗИТЬ(Заказ.ДокументОснование КАК Документ.СчетНаОплату).Дата КАК ДатаСчета
ИЗ
Документ.ЗаказКлиента КАК Заказ
ГДЕ
Заказ.Ссылка = &Ссылка
Часто причиной низкой скорости работы формы в тонком клиенте является не само чтение данных, а избыточный контекст, передаваемый по сети между клиентом и сервером. Разберем правила оптимизации вызовов:
&НаСервереБезКонтекста. При вызове обычной процедуры &НаСервере платформа сериализует и передает на сервер все данные формы (включая все таблицы и коллекции), а затем возвращает их обратно на клиент.ВыборкаИзРезультатаЗапроса через Следующий(), так как он подгружает данные порциями. Выгрузка через Запрос.Выполнить().Выгрузить() оправдана тогда, когда требуется последующий поиск, сортировка или загрузка в табличную часть через метод Загрузить().Применим вызов без контекста на практике:
&НаКлиенте
Процедура СпециалистПриИзменении(Элемент)
// Передаем на сервер только ссылку, не гоняя контекст всей формы по сети
ДанныеСпециалиста = ПолучитьДанныеСпециалистаНаСервере(Объект.Специалист);
// Заполняем реквизиты формы на клиенте
Объект.ГрафикРаботы = ДанныеСпециалиста.ГрафикРаботы;
Объект.Подразделение = ДанныеСпециалиста.Подразделение;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьДанныеСпециалистаНаСервере(СсылкаНаСпециалиста)
Возврат ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
СсылкаНаСпециалиста,
"ГрафикРаботы, Подразделение"
);
КонецФункции
Резюме: обращение к свойствам формы Объект.Реквизит не требует оптимизации и должно оставаться прямым. Разыменование ссылочных полей через точку (Ссылка.Реквизит) в коде заменяем на получение реквизитов запросом или функциями БСП, а в циклах и пакетных обработках используем исключительно прямые запросы к таблицам базы данных.