Как оптимизировать открытие формы документа с большим количеством строк неограниченной длины и хранилищ значений?

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

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

Выясним причину: почему платформа медленно открывает форму

Для понимания сути проблемы проанализируем, как платформа 1С и СУБД работают с тяжелыми полями и объектами данных:

  1. Неделимость считывания объектной модели: В платформе 1С объектная модель построена по принципу неделимости. Когда мы вызываем метод Ссылка.ПолучитьОбъект() или когда в управляемой форме инициализируется основной реквизит Объект типа ДокументОбъект.*, платформа не умеет считывать только часть полей. Сервер 1С генерирует SQL-запрос, считывающий из СУБД все реквизиты шапки документа сразу. Механизма частичного чтения реквизитов объекта в платформе не предусмотрено.
  2. Особенности хранения LOB-данных в СУБД: В современных реляционных базах данных (MS SQL Server, PostgreSQL) поля неограниченной длины и двоичные данные физически не хранятся в общей строке таблицы. Они выносятся в отдельные LOB-страницы или TOAST-таблицы. Считывание таких полей требует от дисковой подсистемы дополнительных операций случайного чтения (Random I/O), что существенно увеличивает нагрузку на сервер и вымывает буферный кэш базы данных.
  3. Сериализация и клиент-серверный трафик: В управляемых формах реквизит Объект целиком сериализуется и отправляется на клиент. Даже если тяжелые строковые поля вынесены на третью или четвертую вкладку, многомегабайтные строки все равно упаковываются в трафик и передаются на тонкий клиент в момент открытия. Это приводит к заметным сетевым лагам.

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

Решение 1. Архитектурное: вынос тяжелых данных в независимый регистр сведений

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

Разберем по шагам, как устроен этот механизм:

  1. Создаем непериодический регистр сведений (например, ДополнительныеДанныеДокументов).
  2. В качестве измерения указываем ссылку на наш документ с включенной галочкой Ведущее (это обеспечит автоматическое удаление записей регистра при удалении самого документа).
  3. В ресурсы регистра переносим поля неограниченной длины и хранилища значений.
  4. Удаляем тяжелые реквизиты из метаданных самого документа.

Благодаря такой структуре чтение самого документа через ПолучитьОбъект() или обращение к его реквизитам через точку (например, Ссылка.Контрагент) больше не считывает гигабайты тяжелого текста. Документ открывается мгновенно, а выборка из регистра выполняется только тогда, когда эти данные действительно нужны.

Если для существующих отчетов требуются некоторые данные (например, краткое примечание), рекомендуется оставить в документе реквизит с ограниченной строкой — например, Строка(250), куда записывать аннотацию, а полный текст хранить исключительно в регистре.

Решение 2. Программное: легкая форма с ленивой загрузкой (Lazy Loading)

Если изменить структуру метаданных невозможно (например, из-за огромного количества типовых или внешних отчетов, завязанных на реквизиты шапки), разберем альтернативное решение — переработку логики формы документа без изменения структуры таблиц базы.

Основная идея: не вычитывать объект целиком при обычном открытии формы для просмотра.

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

Решение 3. Оптимизация работы с типом «ХранилищеЗначения»

Если в документе обязательно должны присутствовать реквизиты типа ХранилищеЗначения (например, форматированные документы или бинарные структуры), важно использовать максимальное сжатие при сохранении данных.

Посмотрим на пример правильной упаковки данных в хранилище:


// Упаковка данных с максимальной степенью сжатия (9)
СтепеньСжатия = Новый СжатиеДанных(9);
Объект.ХранилищеТекста = Новый ХранилищеЗначения(ФорматированнаяСтрока, СтепеньСжатия);

Использование максимальной степени сжатия позволяет значительно уменьшить объем LOB-данных на диске и сократить время их передачи по сети между СУБД и сервером 1С.

При передаче таких данных на форму тонкого клиента не размещайте их в реквизитах формы напрямую: используйте функцию ПоместитьВоВременноеХранилище() с передачей на клиент только строкового адреса.

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

← На главную