Как эффективнее получать данные: через свойства объекта или с помощью запроса?

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

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

Разбор исходной ситуации

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


Данные = Новый Структура;
Данные.Вставить("Проведен", ОбъектОбработки.Проведен);
Данные.Вставить("ПометкаУдаления", ОбъектОбработки.ПометкаУдаления);
Данные.Вставить("Дата", ОбъектОбработки.Дата);
Данные.Вставить("Номер", ОбъектОбработки.Номер);
Данные.Вставить("Склад", ОбъектОбработки.Склад.ИДД);
Данные.Вставить("ИДД", XMLСтрока(ОбъектОбработки));

мсвТаблица = Новый Массив;
Для каждого текСтрока из ОбъектОбработки.Товары цикл
    Товары = Новый Структура;
    Товары.Вставить("Количество", текСтрока.Количество);
    Товары.Вставить("Качество", текСтрока.Качество);
    Товары.Вставить("ХарактеристикаНоменклатуры", текСтрока.ХарактеристикаНоменклатуры.ИДД);
    мсвТаблица.Добавить(Товары);
КонецЦикла;

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

Сценарий 1: Объект уже находится в памяти

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

Рассмотрим особенности:

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

Сценарий 2: Работа со ссылкой (ДокументСсылка)

Ситуация кардинально меняется, если ОбъектОбработки — это ДокументСсылка. Рассмотрим подробнее, что происходит "под капотом" платформы при обращении к ссылке через точку.

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

Но главная проблема кроется в табличных частях. Обращение к Ссылка.Товары всегда инициирует отдельный запрос к базе данных. Если мы обрабатываем массив из 100 документов в цикле и обращаемся к их табличным частям через точку, мы получим 100 дополнительных запросов к СУБД. Это классическая проблема производительности "N+1".

Преимущества использования запроса

Выясним причину, по которой опытные разработчики предпочитают использовать Запрос вместо прямого обращения к свойствам ссылки:

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

Оптимальное решение с использованием запроса

Разобравшись в теории, посмотрим на пример реализации задачи через пакетный запрос. Это позволит нам получить данные шапки и табличной части максимально эффективно.


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

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

// Обработка данных шапки
ВыборкаШапка = РезультатыПакет[0].Выбрать();
Если ВыборкаШапка.Следующий() Тогда
    Данные = Новый Структура;
    ЗаполнитьЗначенияСвойств(Данные, ВыборкаШапка);
    Данные.Вставить("ИДД", XMLСтрока(ВыборкаШапка.Ссылка));
КонецЕсли;

// Обработка табличной части
ВыборкаТЧ = РезультатыПакет[1].Выбрать();
мсвТаблица = Новый Массив;
Пока ВыборкаТЧ.Следующий() Цикл
    СтрокаТЧ = Новый Структура("Количество, Качество, ХарактеристикаНоменклатуры");
    ЗаполнитьЗначенияСвойств(СтрокаТЧ, ВыборкаТЧ);
    СтрокаТЧ.ХарактеристикаНоменклатуры = ВыборкаТЧ.ХарактеристикаИДД;
    мсвТаблица.Добавить(СтрокаТЧ);
КонецЦикла;

В данном примере мы использовали ВыполнитьПакет(), что позволило нам за одно обращение к серверу БД получить все необходимые данные. Обратите внимание на использование функции XMLСтрока(). Если вы работаете со ссылкой, передача ссылки в эту функцию — быстрая операция. Однако, если у вас уже есть объект, получение УникальныйИдентификатор() от ссылки объекта будет более правильным решением.

Рекомендации для практики

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

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

← На главную