При разработке решений для терминалов сбора данных (ТСД) в 1С часто возникает задача оптимизации производительности, особенно когда речь идет о взаимодействии с серверной частью. Одна из таких ситуаций — многократный вызов метода ПолучитьОбъект() при каждом сканировании штрихкода или выполнении операции. Рассмотрим эту проблему подробнее и выясним, как мы можем сократить затрачиваемое время и повысить эффективность работы.
Мы знаем, что метод ПолучитьОбъект() является достаточно ресурсоемкой операцией. При его вызове система полностью считывает все данные объекта из базы данных на сервер, а затем передает их на клиент, включая все табличные части и реквизиты. Эта операция может вызывать блокировку объекта в базе данных, что негативно сказывается на производительности, особенно при большом количестве одновременных пользователей или частых вызовах. Цель нашей оптимизации — минимизировать эти затраты.
Давайте разберем несколько подходов к решению этой задачи, учитывая как производительность, так и потенциальные риски.
Один из самых очевидных способов избежать многократного обращения к базе данных — это сохранить полученный объект непосредственно на форме ТСД. Мы можем единожды получить объект и хранить его в реквизите формы в течение всего времени жизни этой формы.
Как это сделать:
ДокументОбъект.ПеремещениеТоваров.ПолучитьОбъект() и присвойте полученное значение этому реквизиту.ПолучитьОбъект(), мы будем обращаться к данным, которые уже хранятся в реквизите формы.Пример создания реквизита формы:
// В конфигураторе, на форме:
// Создать реквизит формы с именем "ТекущийДокумент"
// Тип: ДокументОбъект.МойДокумент (или ДокументОбъект.ПеремещениеТоваров, и т.д.)
Пример кода в модуле формы:
&НаСервере
Функция ПолучитьИлиКэшироватьДокумент(СсылкаНаДокумент)
// Если объект уже закэширован, возвращаем его
Если ТекущийДокумент <> Неопределено И ТекущийДокумент.Ссылка = СсылкаНаДокумент Тогда
Возврат ТекущийДокумент;
КонецЕсли;
// Иначе получаем объект из базы и кэшируем его
ТекущийДокумент = СсылкаНаДокумент.ПолучитьОбъект();
Возврат ТекущийДокумент;
КонецФункции
&НаКлиенте
Процедура ПриСканированииШтрихкода(Штрихкод)
// Допустим, мы получили СсылкаНаДокумент по штрихкоду
СсылкаНаДокумент = ПолучитьСсылкуПоШтрихкоду(Штрихкод); // Ваша функция для получения ссылки
Если СсылкаНаДокумент <> Неопределено Тогда
ОбъектДокумента = ПолучитьИлиКэшироватьДокумент(СсылкаНаДокумент);
// Теперь мы работаем с ОбъектДокумента, который либо кэширован, либо получен
// Выполняем необходимые операции с ОбъектДокумента
// ...
КонецЕсли;
КонецПроцедуры
Преимущества кэширования на форме:
Недостатки и риски кэширования на форме:
ПолучитьОбъект() (например, для проверки актуальности) все ваши локальные, несохраненные изменения будут потеряны, так как объект будет перезагружен из базы данных.Использование ЗначениеВРеквизитФормы() и РеквизитФормыВЗначение():
Эти методы позволяют более гибко управлять данными, конвертируя объект базы данных в данные формы и обратно. Это может быть полезно для частичной передачи данных или сохранения состояния, но само по себе не решает проблему актуальности данных или производительности при записи. Фактически, РеквизитФормыВЗначение() в контексте сохранения модифицированного объекта в базу ничем не отличается по производительности от ПолучитьОбъект() для создания объекта, если речь идет о записи. Они предназначены для работы с данными формы, а не для оптимизации получения объекта из базы.
Если для выполнения операции на ТСД вам нужна лишь небольшая часть информации из документа, а не полный объект, то получение всего объекта становится избыточным и неэффективным. Вместо этого мы можем получить только те реквизиты, которые нам действительно необходимы.
Суть подхода:
Документы.МойДокумент.ПолучитьДанныеПоСсылке()), если такие методы реализованы в вашей конфигурации и позволяют получить часть данных или агрегированную информацию без полной загрузки объекта.Преимущества:
Пример кода с запросом:
&НаСервере
Функция ПолучитьСтатусДокумента(СсылкаНаДокумент)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документ.Проведен КАК Проведен,
| Документ.Дата КАК Дата,
| Документ.Номер КАК Номер
|ИЗ
| Документ.МойДокумент КАК Документ
|ГДЕ
| Документ.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
Возврат Новый Структура("Проведен, Дата, Номер", Результат.Проведен, Результат.Дата, Результат.Номер);
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
&НаКлиенте
Процедура ПроверитьДокументПоСсылке(СсылкаНаДокумент)
ДанныеДокумента = ПолучитьСтатусДокумента(СсылкаНаДокумент);
Если ДанныеДокумента <> Неопределено Тогда
Сообщить("Документ " + ДанныеДокумента.Номер + " от " + ДанныеДокумента.Дата + " проведен: " + ДанныеДокумента.Проведен);
Иначе
Сообщить("Документ не найден.");
КонецЕсли;
КонецПроцедуры
Этот подход особенно эффективен, когда для проверки или отображения информации на ТСД требуется лишь несколько реквизитов, например, статус документа (проведен или нет), его номер, сумма или ответственный. Мы не загружаем весь объект, а только минимально необходимый набор данных.
В оригинальном обсуждении упоминалась причина частого обращения к ПолучитьОбъект(): защита от потери данных на ТСД в случае его разрядки или сбоя. Если каждое сканирование сопровождается записью изменений в базу, то даже при потере связи ТСД "не потеряет то, что уже отсканировал". Однако это приводит к высокой нагрузке на сервер.
Мы можем пересмотреть эту логику и реализовать механизм накопления отсканированных данных на ТСД, а затем выполнять получение объекта и запись изменений один раз, после завершения всех операций сканирования для данного документа или даже пакета документов.
Суть подхода:
ПолучитьОбъект().Объект.Записать()) в базу данных.Применимость и решение проблемы потери данных:
Этот подход особенно актуален для ТСД, где серия сканирований обычно относится к одному документу (например, при сборке заказа или инвентаризации). Если целью является именно не потерять данные на ТСД в случае его разрядки, то наиболее правильным решением является сохранение данных непосредственно на ТСД. Это можно реализовать несколькими способами:
В таком сценарии ТСД сначала сохраняет все отсканированные данные локально. При первой же возможности (восстановление связи, включение после разрядки) ТСД синхронизирует накопленные данные с сервером 1С. Это обеспечивает устойчивость к сбоям на самом ТСД без постоянной "задрочки" сервера 1С.
Для более сложных сценариев работы с ТСД, где требуется значительная автономность и большой объем данных, мы можем рассмотреть использование механизмов автономной работы или специального обмена данными.
Суть подхода:
Преимущества:
Это более комплексное решение, которое требует дополнительной разработки механизмов обмена, но дает наилучший результат в долгосрочной перспективе для интенсивной работы с ТСД.
Важно уточнить, что термин "Повторное использование на сеанс", который упоминался в обсуждении, чаще относится к механизмам HTTP-сервисов и веб-сервисов 1С. Он позволяет сохранять состояние между вызовами в рамках одного HTTP-сеанса на сервере, что может быть полезно для оптимизации серверных вызовов в stateless-среде. Однако это не применимо для прямого кэширования объектов на форме управляемого приложения в контексте, который мы обсуждаем. Для формы мы используем реквизиты формы, как было описано в первом пункте.
Выбор оптимального метода оптимизации ПолучитьОбъект() зависит от конкретных требований к актуальности данных, производительности и устойчивости к сбоям на ТСД. Мы рекомендуем следующие шаги:
ПолучитьОбъект().Наиболее эффективным часто является гибридный подход: мы получаем только необходимые данные для оперативного отображения и базовой проверки, а полный объект получаем или записываем только один раз в конце цикла работы с ним, с учетом потенциальных конфликтов данных и механизмов их разрешения.