Как правильно оптимизировать обращения к данным через точку и запросы в 1С:Предприятие 8.3

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

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

1. Разница между обращением к реквизитам формы и разыменованием ссылок

Рассмотрим две принципиально разные ситуации, которые часто ошибочно объединяют под общим понятием «обращение через точку»:

  1. Обращение к реквизиту формы (основному реквизиту Объект): конструкция вида Специалист = Объект.Специалист; на сервере формы обращается к данным, которые уже находятся в оперативной памяти текущего сеанса. Платформа не выполняет дополнительных запросов к СУБД для чтения этого поля. Более того, чтение через запрос в данном случае вернет данные из базы, а не текущие несохраненные изменения пользователя.
  2. Разыменование ссылки (обращение через две точки): конструкция вида График = Объект.Специалист.ГрафикРаботы; приводит к тому, что платформа берет ссылку Объект.Специалист и считывает из базы данных весь объект справочника целиком в сеансовый кэш, чтобы получить одно значение.

Посмотрим на наглядный пример в коде модуля формы:


&НаСервере
Процедура ОбработатьДанныеНаСервере()
    
    // ВАРИАНТ 1: Допустимо и быстро.
    // Значение реквизита берется напрямую из структуры данных формы в памяти.
    ТекущийСпециалист = Объект.Специалист;
    
    // ВАРИАНТ 2: Неоптимально (неявный запрос и считывание всего объекта).
    // Происходит чтение всех реквизитов шапки справочника "Специалисты".
    График = Объект.Специалист.ГрафикРаботы;
    
    // ВАРИАНТ 3: Оптимально для получения реквизитов связанных объектов.
    // Выбираются только необходимые поля без чтения объекта целиком.
    График = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ТекущийСпециалист, "ГрафикРаботы");

КонецПроцедуры

2. Когда использовать объектное чтение, а когда запросы

Разберем основные сценарии и определим правила выбора подхода:

  1. Пользовательские интерактивные сценарии: когда пользователь работает с одной конкретной формой, обращение к небольшому числу реквизитов ссылок может отрабатывать быстро за счет серверного кэша объектов. Однако хорошим тоном остается использование функции ОбщегоНазначения.ЗначениеРеквизитаОбъекта() или ОбщегоНазначения.ЗначенияРеквизитовОбъекта() (для нескольких полей).
  2. Массовая обработка данных и циклы: категорически запрещено разыменовывать ссылки через точку внутри циклов (например, при обходе строк таблицы или выборки). Обращение к полям 1000 элементов через точку сгенерирует 1000 отдельных неявных обращений к базе и засорит кэш сеанса, вытесняя полезные данные. В таких сценариях выборка выполняется исключительно единым запросом.
  3. Несохраненные данные: если алгоритм должен учитывать текущие введенные пользователем данные, которые еще не записаны в базу, обращение к реквизитам формы через Объект.ИмяРеквизита является единственно верным решением.

3. Особенности обращений через точку в текстах запросов

Проанализируем механику работы языка запросов 1С при обращении к полям через точку (например, ПланРабот.Специалист.ГрафикРаботы):

Платформа автоматически транслирует такие конструкции в инструкции LEFT OUTER JOIN (левое внешнее соединение) к таблице СУБД. Однако здесь присутствуют важные нюансы:

  1. Дублирование соединений: если в секции ВЫБРАТЬ, ГДЕ или УПОРЯДОЧИТЬ ПО неоднократно обращаться через точку к разным полям одной и той же ссылки, платформа может сформировать несколько одинаковых соединений с одной таблицей, усложняя план выполнения запроса. Явное левое соединение (ЛЕВОЕ СОЕДИНЕНИЕ) позволяет точно контролировать структуру запроса.
  2. Поля составного типа: обращение через точку к реквизиту составного типа крайне опасно. Платформа построит левые соединения со всеми таблицами, входящими в составной тип, а также добавит ветвление CASE WHEN. Для исключения этой проблемы обязательно применяем оператор ВЫРАЗИТЬ.

Посмотрим на пример правильного ограничения типа в запросе:


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

4. Оптимизация клиент-серверного взаимодействия в тонком клиенте

Часто причиной низкой скорости работы формы в тонком клиенте является не само чтение данных, а избыточный контекст, передаваемый по сети между клиентом и сервером. Разберем правила оптимизации вызовов:

  1. Переход на вызовы без контекста: если для выполнения серверного действия не требуется изменять саму форму, всегда используем директиву &НаСервереБезКонтекста. При вызове обычной процедуры &НаСервере платформа сериализует и передает на сервер все данные формы (включая все таблицы и коллекции), а затем возвращает их обратно на клиент.
  2. Минимизация обращений к серверу: объединяем несколько серверных вызовов в один комплексный метод, возвращающий структуру с нужными данными.
  3. Пакетная работа с выборками: при необходимости последовательного чтения данных в памяти эффективнее использовать обход объекта ВыборкаИзРезультатаЗапроса через Следующий(), так как он подгружает данные порциями. Выгрузка через Запрос.Выполнить().Выгрузить() оправдана тогда, когда требуется последующий поиск, сортировка или загрузка в табличную часть через метод Загрузить().

Применим вызов без контекста на практике:


&НаКлиенте
Процедура СпециалистПриИзменении(Элемент)
    
    // Передаем на сервер только ссылку, не гоняя контекст всей формы по сети
    ДанныеСпециалиста = ПолучитьДанныеСпециалистаНаСервере(Объект.Специалист);
    
    // Заполняем реквизиты формы на клиенте
    Объект.ГрафикРаботы = ДанныеСпециалиста.ГрафикРаботы;
    Объект.Подразделение = ДанныеСпециалиста.Подразделение;

КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДанныеСпециалистаНаСервере(СсылкаНаСпециалиста)
    
    Возврат ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
        СсылкаНаСпециалиста, 
        "ГрафикРаботы, Подразделение"
    );

КонецФункции

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

← На главную