При разработке на платформе 1С:Предприятие 8.3 одной из самых частых задач является массовая обработка документов. Однако неправильное использование метода ПолучитьОбъект() может привести к существенному замедлению работы системы, блокировкам базы данных и избыточному потреблению оперативной памяти сервером rphost. В этой статье мы подробно разберем, как минимизировать нагрузку на систему и когда именно стоит переходить от ссылки к объекту.
Метод ПолучитьОбъект() — это «тяжелая» операция. Когда мы вызываем его, платформа выполняет целый ряд действий:
Если ваша задача — просто проверить условие в табличной части, получение всего объекта для тысяч документов в цикле создаст колоссальную нагрузку. Рассмотрим, как этого избежать.
Проанализируем самый эффективный способ: не выбирать лишние данные. Вместо того чтобы получать все незакрытые заказы и проверять условия в коде 1С, мы должны перенести всю логику проверки в текст запроса. Если нам нужно изменить только те заказы, где есть строки с определенным товаром или статусом, запрос должен возвращать только эти ссылки.
Рассмотрим пример кода, где мы получаем данные табличной части сразу в запросе, чтобы не обращаться к объекту без нужды:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказКлиента.Ссылка КАК Ссылка
|ИЗ
| Документ.ЗаказКлиента КАК ЗаказКлиента
|ГДЕ
| ЗаказКлиента.Проведен = ИСТИНА
| И ЗаказКлиента.Товары.Отменено = ЛОЖЬ
| И ЗаказКлиента.Товары.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", СсылкаНаТовар);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Мы точно знаем, что этот объект НУЖНО менять
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
// Логика изменения строк
ДокОбъект.Записать();
КонецЦикла;
Бывают ситуации, когда логика проверки слишком сложна для языка запросов. В этом случае проанализируем подход с предварительной проверкой. Мы сначала получаем данные через ссылку (через точку или отдельным запросом к ТЧ), и только если понимаем, что изменения неизбежны, вызываем ПолучитьОбъект().
Разберем по шагам предложенный на форуме вариант:
Модифицированность.ПолучитьОбъект() только при истинности флага.
// Пример "умного" получения объекта
Пока ВыборкаДокументов.Следующий() Цикл
НужноРедактировать = Ложь;
// Проверяем условия через данные запроса (не через объект!)
Для Каждого СтрокаТЧ Из ВыборкаДокументов.ТабличнаяЧасть Цикл
Если СтрокаТЧ.УсловиеВыполнено Тогда
НужноРедактировать = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если НужноРедактировать Тогда
ДокОбъект = ВыборкаДокументов.Ссылка.ПолучитьОбъект();
// Производим действия
ДокОбъект.Записать();
КонецЕсли;
КонецЦикла;
Малоизвестный, но крайне эффективный метод для массовой обработки — Документы.ЗаказКлиента.ВыбратьПоСсылкам(МассивСсылок). Выясним причину его эффективности: в отличие от обращения в цикле, этот метод оптимизирует получение данных на уровне платформы, уменьшая количество «походов» к серверу базы данных. Это особенно актуально, если вам нужно прочитать данные объектов перед их возможным изменением.
Проанализируем ситуацию с многопользовательской работой. Если мы сначала проверяем условие запросом, а потом получаем объект, между этими событиями данные в базе могут быть изменены другим пользователем. Чтобы избежать логических ошибок, придерживаемся следующих правил:
БлокировкаДанных на нужные ссылки.Записать() полезно проверить ДокОбъект.Модифицированность(). Если данные по факту не изменились, запись можно пропустить.Важно понимать разницу, когда мы работаем с данными. Запрос возвращает результат в виде ВыборкаИзРезультатаЗапроса или ТаблицаЗначений. Это просто наборы данных в памяти. ТабличнаяЧасть документа (доступная через ПолучитьОбъект()) — это объектная структура, связанная с метаданными. Для анализа данных всегда выгоднее использовать РезультатЗапроса, так как он не тянет за собой весь контекст объекта и методы модуля объекта.
Рассмотрим пример правильного получения ТЧ через запрос без получения объекта:
Запрос = Новый Запрос(
"ВЫБРАТЬ
| ЗаказТовары.Номенклатура,
| ЗаказТовары.Количество
|ИЗ
| Документ.ЗаказКлиента.Товары КАК ЗаказТовары
|ГДЕ
| ЗаказТовары.Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", ТекущаяСсылка);
ТЗ_Товары = Запрос.Выполнить().Выгрузить(); // Это намного быстрее, чем Ссылка.ПолучитьОбъект().Товары.Выгрузить()
Подводя итог, сформулируем основные правила работы с ПолучитьОбъект():
ПолучитьОбъект(), если вам нужно просто прочитать реквизит или строку табличной части. Используйте запросы или обращение через точку (помня о неявных запросах).Записать().ДополнительныеСвойства объекта для передачи флагов в модуль объекта, чтобы отключить ненужные при программной обработке проверки.Соблюдение этих простых правил позволит вашим обработкам летать, а серверу 1С — дышать свободно даже при обработке миллионов заказов.