Как эффективно выгрузить 2 миллиона строк через СКД без переполнения памяти?

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

Работа с большими объемами данных в системе компоновки данных (СКД) часто ставит перед разработчиком непростую задачу. Когда количество строк в результате запроса достигает нескольких миллионов, стандартные механизмы вывода в табличный документ начинают потреблять колоссальный объем оперативной памяти, что приводит к зависанию сессии или аварийному завершению работы 1С с ошибкой «Недостаточно памяти». Разберем подробно, почему это происходит и как оптимизировать процесс выгрузки, чтобы обработка 2–2.5 млн строк стала стабильной и быстрой.

Почему тормозит вывод в СКД?

Проанализируем архитектуру процесса вывода. В 1С ТабличныйДокумент — это не просто текстовая сетка, а сложный объект. Каждая ячейка в нем обладает множеством свойств: оформление, шрифты, параметры расшифровки. Когда мы выводим 2 миллиона строк, платформа создает в памяти миллионы объектов. Если при этом включена расшифровка, система дополнительно хранит карту соответствий между ячейками и данными, что увеличивает потребление ресурсов в геометрической прогрессии. Даже на 64-битном сервере формирование такого отчета может занимать часы из-за нагрузки на менеджер памяти и сборщик мусора.

Решение 1. Отключение расшифровки и условного оформления

Первый и самый важный шаг при программном формировании тяжелых отчетов — полный отказ от механизмов расшифровки и сложного оформления. Рассмотрим, как правильно инициализировать ПроцессорКомпоновкиДанных. Обратите внимание на третий параметр метода Инициализировать — он отвечает за данные расшифровки. Если передать туда Неопределено или пустое значение и установить четвертый параметр (возможность использования внешних функций) в Ложь, потребление памяти существенно снизится.

Разберем пример кода для оптимизированной инициализации:


// Создаем схему и настройки
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();

// Формируем макет компоновки БЕЗ расшифровки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

// Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Третий параметр - НЕ передаем объект данных расшифровки
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , , Ложь);

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

Решение 2. Вывод в таблицу значений вместо табличного документа

Если задача состоит в том, чтобы просто получить данные для последующей обработки, рассмотрим вариант вывода результата в ТаблицаЗначений. Это работает быстрее, чем формирование ТабличногоДокумента, так как в таблице значений отсутствуют визуальные свойства ячеек. Однако стоит помнить, что при 2 млн строк сама таблица в памяти также может занять значительный объем (около 2-4 ГБ в зависимости от количества колонок).

Для реализации этого метода используем ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений:


РезультатТЗ = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(РезультатТЗ);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

Решение 3. Самый эффективный метод: получение «чистого» запроса

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

Рассмотрим, как извлечь запрос из макета компоновки:


// Получаем макет компоновки (как в первом примере)
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);

// В макете компоновки для набора данных типа "Запрос" содержится готовый текст
ТекстЗапроса = МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос;

// Создаем обычный объект Запрос
Запрос = Новый Запрос(ТекстЗапроса);

// Переносим параметры из макета компоновки в запрос
Для Каждого ПараметрМакеты Из МакетКомпоновки.ЗначенияПараметров Цикл
    Запрос.УстановитьПараметр(ПараметрМакеты.Имя, ПараметрМакеты.Значение);
КонецЦикла;

// Выполняем запрос и обходим результат
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

ФайлВыгрузки = Новый ЗаписьТекста("C:\Export\data.csv", КодировкаТекста.UTF8);
Пока Выборка.Следующий() Цикл
    // Формируем строку и записываем её
    СтрокаДанных = Строка(Выборка.Код) + ";" + Выборка.Наименование; 
    ФайлВыгрузки.ЗаписатьСтроку(СтрокаДанных);
КонецЦикла;
ФайлВыгрузки.Закрыть();

Проанализируем преимущества данного подхода:

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

Дополнительные рекомендации

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

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

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

← На главную