Многие разработчики сталкиваются с задачей оптимизации работы с большими объемами данных в управляемых формах. Естественное желание — один раз выполнить тяжелый запрос, поместить результат во Временную таблицу (МВТ) и затем быстро фильтровать или группировать эти данные при каждом действии пользователя. Однако при попытке реализовать это «в лоб» мы сталкиваемся с тем, что МенеджерВременныхТаблиц не сохраняется между серверными вызовами.
Давайте подробно разберем, почему так происходит, и какие архитектурные решения помогут нам достичь поставленной цели без нарушения принципов работы платформы 1С.
МенеджерВременныхТаблиц нельзя сохранить?Важно понимать, что МенеджерВременныхТаблиц — это объект, работающий в рамках текущего контекста исполнения на сервере 1С. Когда выполняется серверный вызов, 1С открывает сессию с СУБД. Временные таблицы (#TemporaryTable) создаются на стороне SQL-сервера и существуют исключительно в рамках этой конкретной сессии. Как только серверный вызов завершается, 1С освобождает ресурсы, соединение возвращается в пул, а СУБД автоматически удаляет все временные таблицы. Сериализовать «живой» указатель на объект СУБД невозможно.
РегистраСведений для временных данныхЕсли данные необходимо часто фильтровать и они занимают большой объем, самым надежным решением является использование физических таблиц в базе данных. Создайте специальный РегистрСведений (непериодический, независимый), который будет служить «буфером» для ваших промежуточных расчетов.
УникальныйИдентификаторСеанса (тип УникальныйИдентификатор), чтобы данные разных пользователей не перемешивались.РегистраСведений с отбором по вашему идентификатору.Этот метод позволяет полноценно использовать индексы СУБД, что обеспечивает высокую производительность даже при работе с миллионами строк.
// Пример записи данных для текущего сеанса
НаборЗаписей = РегистрыСведений.ВременныеДанные.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИдентификаторСеанса.Установить(УникальныйИдентификаторСеанса);
Для Каждого СтрокаТЗ Из РезультатЗапроса Цикл
Запись = НаборЗаписей.Добавить();
Запись.ИдентификаторСеанса = УникальныйИдентификаторСеанса;
Запись.КодТовара = СтрокаТЗ.КодТовара;
// ... прочие поля
КонецЦикла;
НаборЗаписей.Записать();
ВременногоХранилищаЕсли объем данных не критически велик (например, до нескольких десятков тысяч записей), мы можем воспользоваться механизмом ВременногоХранилища. В этом случае мы сериализуем таблицу в структуру или саму ТаблицуЗначений.
Рассмотрим порядок действий:
ТаблицуЗначений.ВременноеХранилище с помощью функции ПоместитьВоВременноеХранилище().Адрес (строку-ключ), которую передаем на клиент (в реквизит формы).Адрес обратно, считываем данные из хранилища и при необходимости создаем новую временную таблицу в текущем МенеджереВременныхТаблиц.Важное примечание: При каждом вызове происходит десериализация данных, что требует времени. Поэтому данный метод стоит использовать только для среднего объема данных.
Часто проблема возникает из-за того, что мы пытаемся хранить данные «на будущее», вместо того чтобы пересчитать их оптимально. Проанализируем ситуацию: возможно, стоит пересмотреть структуру запроса, используя вложенные запросы или пакетные запросы. Современные СУБД очень эффективно работают с кэшированием планов запросов. Если вы построите запрос так, что он будет выполняться быстро с передачей параметров, необходимость в удержании МенеджераВременныхТаблиц может отпасть сама собой.
В ходе дискуссий часто предлагают использовать «вечные» фоновые задания с бесконечными циклами для удержания контекста сеанса. Мы настоятельно рекомендуем избегать такой практики. Это приводит к:
Подводя итог: лучшее решение — это сохранение данных в базу (РегистрСведений) с последующей очисткой по завершении работы пользователя. Это архитектурно чистый путь, который гарантирует стабильность и предсказуемое поведение системы.