Как оптимизировать частое использование ПолучитьОбъект() при работе с терминалами сбора данных в 1С?

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

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

Мы знаем, что метод ПолучитьОбъект() является достаточно ресурсоемкой операцией. При его вызове система полностью считывает все данные объекта из базы данных на сервер, а затем передает их на клиент, включая все табличные части и реквизиты. Эта операция может вызывать блокировку объекта в базе данных, что негативно сказывается на производительности, особенно при большом количестве одновременных пользователей или частых вызовах. Цель нашей оптимизации — минимизировать эти затраты.

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

1. Кэширование объекта в реквизите формы

Один из самых очевидных способов избежать многократного обращения к базе данных — это сохранить полученный объект непосредственно на форме ТСД. Мы можем единожды получить объект и хранить его в реквизите формы в течение всего времени жизни этой формы.

Как это сделать:

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

Пример создания реквизита формы:


// В конфигураторе, на форме:
// Создать реквизит формы с именем "ТекущийДокумент"
// Тип: ДокументОбъект.МойДокумент (или ДокументОбъект.ПеремещениеТоваров, и т.д.)

Пример кода в модуле формы:


&НаСервере
Функция ПолучитьИлиКэшироватьДокумент(СсылкаНаДокумент)

    // Если объект уже закэширован, возвращаем его
    Если ТекущийДокумент <> Неопределено И ТекущийДокумент.Ссылка = СсылкаНаДокумент Тогда
        Возврат ТекущийДокумент;
    КонецЕсли;

    // Иначе получаем объект из базы и кэшируем его
    ТекущийДокумент = СсылкаНаДокумент.ПолучитьОбъект();
    Возврат ТекущийДокумент;

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

&НаКлиенте
Процедура ПриСканированииШтрихкода(Штрихкод)
    // Допустим, мы получили СсылкаНаДокумент по штрихкоду
    СсылкаНаДокумент = ПолучитьСсылкуПоШтрихкоду(Штрихкод); // Ваша функция для получения ссылки

    Если СсылкаНаДокумент <> Неопределено Тогда
        ОбъектДокумента = ПолучитьИлиКэшироватьДокумент(СсылкаНаДокумент);
        // Теперь мы работаем с ОбъектДокумента, который либо кэширован, либо получен
        // Выполняем необходимые операции с ОбъектДокумента
        // ...
    КонецЕсли;
КонецПроцедуры

Преимущества кэширования на форме:

Недостатки и риски кэширования на форме:

Использование ЗначениеВРеквизитФормы() и РеквизитФормыВЗначение():

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

2. Чтение только необходимых данных через запросы или методы менеджера

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

Суть подхода:

  1. Используйте объект "Запрос" для выборочного чтения данных из базы. Мы можем получить только конкретные реквизиты документа или его табличных частей.
  2. Воспользуйтесь методами менеджера объекта (например, Документы.МойДокумент.ПолучитьДанныеПоСсылке()), если такие методы реализованы в вашей конфигурации и позволяют получить часть данных или агрегированную информацию без полной загрузки объекта.

Преимущества:

Пример кода с запросом:


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

&НаКлиенте
Процедура ПроверитьДокументПоСсылке(СсылкаНаДокумент)
    ДанныеДокумента = ПолучитьСтатусДокумента(СсылкаНаДокумент);
    Если ДанныеДокумента <> Неопределено Тогда
        Сообщить("Документ " + ДанныеДокумента.Номер + " от " + ДанныеДокумента.Дата + " проведен: " + ДанныеДокумента.Проведен);
    Иначе
        Сообщить("Документ не найден.");
    КонецЕсли;
КонецПроцедуры

Этот подход особенно эффективен, когда для проверки или отображения информации на ТСД требуется лишь несколько реквизитов, например, статус документа (проведен или нет), его номер, сумма или ответственный. Мы не загружаем весь объект, а только минимально необходимый набор данных.

3. Отложенное получение объекта или запись данных (аккумулирование изменений)

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

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

Суть подхода:

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

Применимость и решение проблемы потери данных:

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

В таком сценарии ТСД сначала сохраняет все отсканированные данные локально. При первой же возможности (восстановление связи, включение после разрядки) ТСД синхронизирует накопленные данные с сервером 1С. Это обеспечивает устойчивость к сбоям на самом ТСД без постоянной "задрочки" сервера 1С.

4. Механизмы автономной работы или обмена данными

Для более сложных сценариев работы с ТСД, где требуется значительная автономность и большой объем данных, мы можем рассмотреть использование механизмов автономной работы или специального обмена данными.

Суть подхода:

Преимущества:

Это более комплексное решение, которое требует дополнительной разработки механизмов обмена, но дает наилучший результат в долгосрочной перспективе для интенсивной работы с ТСД.

5. Повторное использование на сеанс (для HTTP-сервисов)

Важно уточнить, что термин "Повторное использование на сеанс", который упоминался в обсуждении, чаще относится к механизмам HTTP-сервисов и веб-сервисов 1С. Он позволяет сохранять состояние между вызовами в рамках одного HTTP-сеанса на сервере, что может быть полезно для оптимизации серверных вызовов в stateless-среде. Однако это не применимо для прямого кэширования объектов на форме управляемого приложения в контексте, который мы обсуждаем. Для формы мы используем реквизиты формы, как было описано в первом пункте.

Ключевые рекомендации и заключение

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

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

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

← На главную