Произойдет ли повторное чтение данных из базы при обращении к разным реквизитам одной ссылки?

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

В процессе разработки на платформе 1С:Предприятие 8 часто возникает вопрос: насколько эффективно обращение к реквизитам объекта через точку от ссылки? Например, если мы сначала проверяем Номенклатура.Код, а затем обращаемся к Номенклатура.Производитель, будет ли система дважды запрашивать данные у СУБД? Давайте подробно разберем этот механизм, выясним причины возможных задержек и проанализируем лучшие практики оптимизации такого кода.

Механизм объектного кэша: как 1С работает «под капотом»

Разберем ситуацию, описанную в исходном примере. Проанализируем, что происходит, когда выполняется следующий код:


Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Знч.nom_id));
Если ЗначениеЗаполнено(Номенклатура.Код) Тогда 
    Если Номенклатура.Производитель <> Производитель Тогда 
        Продолжить;
    КонецЕсли;
КонецЕсли;

В первой строке мы просто создаем объект типа СправочникСсылка в памяти. На этом этапе обращения к базе данных не происходит. Платформа просто записывает GUID ссылки.

Самое интересное начинается во второй строке при обращении к Номенклатура.Код. Выясним, как ведет себя платформа:

  1. При первом обращении к любому реквизиту (кроме самой ссылки) через точку, платформа проверяет наличие данных этого объекта в объектном кэше.
  2. Если данных в кэше нет, выполняется запрос к СУБД. Важно понимать, что 1С не запрашивает только поле Код. Платформа выполняет запрос вида SELECT *, считывая все реквизиты справочника (за исключением полей неограниченной длины и хранилищ значения).
  3. Все полученные данные помещаются в кэш.

Таким образом, когда в следующей строке мы обращаемся к Номенклатура.Производитель, повторного чтения из таблицы базы данных не произойдет. Данные будут мгновенно получены из оперативной памяти (кэша). Однако, несмотря на наличие кэша, такой подход может быть крайне неоптимальным.

Почему обращение «через точку» может тормозить?

Если мы проанализируем замер производительности, то увидим, что строка Если ЗначениеЗаполнено(Номенклатура.Код) Тогда отнимает значительное время. Это происходит потому, что именно в этот момент инициируется сетевой запрос к базе данных и ожидание ответа.

Рассмотрим основные проблемы «объектной техники»:

Решение 1: Использование запросов (рекомендуемый способ)

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

Проанализируем пример оптимизированного кода:


// 1. Сначала собираем все ID в массив
МассивСсылок = Новый Массив;
Для Каждого Знч Из СписокЗначений Цикл
    МассивСсылок.Добавить(Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Знч.nom_id)));
КонецЦикла;

// 2. Одним запросом получаем все нужные данные
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка,
    |	Номенклатура.Код КАК Код,
    |	Номенклатура.Производитель КАК Производитель
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Ссылка В(&МассивСсылок)";

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

// 3. Выгружаем в соответствие для быстрого поиска в памяти
ДанныеНоменклатуры = Новый Соответствие;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    СтруктураДанных = Новый Структура("Код, Производитель", Выборка.Код, Выборка.Производитель);
    ДанныеНоменклатуры.Вставить(Выборка.Ссылка, СтруктураДанных);
КонецЦикла;

Теперь в основном цикле обработки нам достаточно обратиться к Соответствию, что происходит мгновенно и не требует обращения к БД.

Решение 2: Метод ПолучитьЗначенияОбъекта()

Начиная с версии платформы 8.3.6, появился более легкий способ получения нескольких реквизитов без использования полноценного запроса и без чтения всех полей объекта. Рассмотрим метод ПолучитьЗначенияОбъекта().

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


СписокРеквизитов = "Код, Производитель";
Значения = ОбщегоНазначения.ПолучитьЗначенияОбъекта(СсылкаНаНоменклатуру, СписокРеквизитов);

Если ЗначениеЗаполнено(Значения.Код) Тогда
    Если Значения.Производитель <> ИскомыйПроизводитель Тогда
        // Логика обработки
    КонецЕсли;
КонецЕсли;

Важный нюанс: Хотя этот метод работает быстрее, чем обращение через точку (так как не читает лишние поля), он всё равно делает отдельный запрос к СУБД для каждой ссылки. Поэтому для циклов он всё еще проигрывает классическому запросу с оператором В (&Массив).

Особенности работы с «битыми» ссылками

Выясним причину, по которой код автора может работать медленно, если ссылки не существуют в базе. Если GUID, переданный в Новый УникальныйИдентификатор, не соответствует ни одной записи, то при обращении к Номенклатура.Код платформа все равно попытается найти этот объект в БД.

По результатам поиска платформа поймет, что объекта нет, и закеширует для этой ссылки «пустые значения». При повторном обращении к этой же несуществующей ссылке запроса не будет, но самый первый «холостой» запрос всё равно будет выполнен и отнимет время.

Итоги и рекомендации

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

  1. Никогда не используйте обращение через точку в циклах. Это приводит к лавинообразному росту количества запросов к базе данных.
  2. Помните про кэш. Одиночное обращение к Ссылка.Реквизит1 и следом к Ссылка.Реквизит2 не вызовет второго запроса, но вызовет избыточное чтение всех полей в первом запросе.
  3. Используйте запросы. Это универсальный стандарт де-факто для оптимизации. Получение данных списком всегда быстрее, чем по одному.
  4. Профилируйте код. Если вы видите, что проверка ЗначениеЗаполнено() или простое сравнение реквизитов работает долго — это первый сигнал к тому, что пора переходить на использование запроса или Соответствия.

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

← На главную