Как ускорить формирование отчета в 1С при зависании из-за ссылочных полей и получения представлений

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

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

Выясним причину такого поведения платформы 1С и разберем практические способы оптимизации.

Почему падает производительность при выводе ссылок

Разберем детально, что происходит «под капотом» платформы 1С при выводе ссылочных типов данных в отчет:

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

Вариант 1. Замена ссылочного поля строковым представлением в запросе

Самый эффективный способ исключить влияние модулей менеджеров на производительность отчета — отказаться от вывода ссылочного типа и сформировать строковое представление непосредственно в теле запроса СУБД. Посмотрим на пример:


ВЫБРАТЬ
    Регистр.Период КАК Период,
    Регистр.Номенклатура КАК Номенклатура,
    // Получаем строковое представление стандартным механизмом СУБД:
    ПРЕДСТАВЛЕНИЕ(Регистр.ДокументДвижения) КАК ДокументПредставление,
    // Либо формируем строку из простых полей документа:
    "№ " + Документ.Номер + " от " + ФОРМАТ(Документ.Дата, "ДФ=dd.MM.yyyy") КАК ДокументСтрока
ИЗ
    РегистрСведений.ИсторияСтатусов КАК Регистр
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ИзменениеСтатуса КАК Документ
        ПО Регистр.ДокументДвижения = Документ.Ссылка

При таком подходе платформа не инициализирует события модуля менеджера, а сервер СУБД выполняет соединение и форматирование строк на порядки быстрее.

Вариант 2. Переопределение выражения представления в СКД

Если отчет строится с использованием схемы компоновки данных (СКД), мы можем переопределить стандартный механизм получения представления прямо на вкладке «Наборы данных».

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

  1. Откроем схему компоновки данных и перейдем на вкладку «Наборы данных».
  2. Найдем поле, содержащее ссылку на документ (например, ДокументДвижения).
  3. В колонке «Выражение представления» укажем конкретное выражение без вызова тяжелых функций, например: "№ " + ДокументДвижения.Номер или имя заранее подготовленного в запросе строкового поля ДокументПредставление.
  4. В настройках отчета отключим автоопределение расшифровки, если интерактивный переход в документ из отчета не требуется.

Вариант 3. Оптимизация процедур получения представлений по стандартам 1С

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


// В модуле менеджера документа:

Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Указываем только простые реквизиты, необходимые для формирования строки
    Поля.Добавить("Номер");
    Поля.Добавить("Дата");
    Поля.Добавить("ВидОперации");
    
КонецПроцедуры

Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Формируем строку исключительно из переданной структуры Данные,
    // без выполнения запросов и обращений через точку
    Представление = СтрШаблон("Документ № %1 от %2 (%3)", 
        Данные.Номер, 
        Формат(Данные.Дата, "ДФ=dd.MM.yyyy"), 
        Данные.ВидОперации);
        
КонецПроцедуры

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

Вариант 4. Потоковая выгрузка данных большого объема

Если конечной целью построения отчета на 600 000+ строк является получение данных во внешнем формате (например, Excel или CSV), вывод такого массива в экранный ТабличныйДокумент является архитектурной ошибкой. Это гарантированно вызовет пиковое потребление RAM и риск аварийного завершения рабочего процесса сервера.

Для таких задач используем потоковую запись выборки запроса с помощью объекта ЗаписьТекста:


Запись = Новый ЗаписьТекста("C:\Export\Data.csv", КодировкаТекста.UTF8);

// Записываем заголовок
Запись.ЗаписатьСтроку("Номенклатура;Документ;Дата");

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    СтрокаДанных = СтрШаблон("%1;%2;%3", 
        Выборка.НоменклатураНаименование, 
        Выборка.ДокументПредставление, 
        Формат(Выборка.Период, "ДФ=dd.MM.yyyy"));
    Запись.ЗаписатьСтроку(СтрокаДанных);
КонецЦикла;

Запись.Закрыть();

Потоковая запись потребляет фиксированный минимальный объем оперативной памяти независимо от того, сколько строк выгружается — 10 000 или 1 000 000.

← На главную