При выгрузке больших массивов данных (десятки и сотни тысяч строк) из 1С в текстовые форматы (CSV, TXT) разработчики часто сталкиваются со значительным падением производительности. Запрос к базе данных может выполняться за 1–2 секунды, однако последующий обход выборки и формирование файла занимает несколько минут. Проанализируем ключевые причины замедления и разберем эффективные способы оптимизации этого процесса.
Выясним основные причины, из-за которых обработка данных во встроенном языке 1С может занимать непропорционально много времени:
Выборка.Номенклатура.ПолноеНаименование или вызовы свойств ссылочных объектов внутри цикла провоцируют дополнительные неявные запросы к базе данных на каждой итерации. При 40 000 строк это приводит к 40 000 дополнительных обращений к СУБД.Стр = Стр + Символ + Значение) платформа регулярно выделяет новые блоки оперативной памяти, что приводит к ее фрагментации и дополнительной нагрузке на сборщик мусора.ТекстовыйДокумент при вызове метода ДобавитьСтроку() расходует больше ресурсов на внутреннюю структуризацию данных, чем специализированный объект ЗаписьТекста.Рассмотрим основной подход к ускорению — максимальное вычисление данных на стороне СУБД с помощью языка запросов 1С.
Проанализируем пример кода с исходной проблемой, где обработка и обращения через точку находились внутри цикла обхода:
Пока Выборка.Следующий() Цикл
Стр = "" + Выборка.ШтрихКод;
Стр = Стр + Символ(166) + Выборка.Номенклатура; // Ссылочный тип
// Проблема: обращение через точку в цикле провоцирует запрос к БД
ПроверкаПодарка = СтрНайти(СокрЛП(Выборка.Номенклатура.ПолноеНаименование), "ПОДАРКИ") > 0;
Если ПроверкаПодарка Тогда
Цена = 0;
Иначе
Цена = Формат(Выборка.РозничнаяЦена, "ЧГ=");
КонецЕсли;
ТекстДок.ДобавитьСтроку(Стр);
КонецЦикла;
Чтобы избавиться от накладных расходов, перенесем получение текстовых представлений ссылок и проверку условий в текст запроса. Воспользуемся функциями ПРЕДСТАВЛЕНИЕ() и оператором ВЫБОР КОГДА ... ИНАЧЕ ... КОНЕЦ:
ВЫБРАТЬ
Товары.ШтрихКод КАК ШтрихКод,
ПРЕДСТАВЛЕНИЕ(Товары.Номенклатура) КАК НоменклатураПредставление,
ПРЕДСТАВЛЕНИЕ(Товары.Производитель) КАК ПроизводительПредставление,
ВЫБОР
КОГДА Товары.Номенклатура.ПолноеНаименование ПОДОБНО "%ПОДАРКИ, ТЕСТЕРЫ, ОБОРУДОВАНИЕ%"
ТОГДА 0
ИНАЧЕ Товары.РозничнаяЦена
КОНЕЦ КАК РозничнаяЦенаВычисленная,
ВЫБОР
КОГДА Товары.Объем * 1000000 > 0.0001
ТОГДА Товары.Объем * 1000000
ИНАЧЕ 1
КОНЕЦ КАК ОбъемВычисленный
ИЗ
РегистрСведений.Товары КАК Товары
Результат: Замена обращения к реквизитам через точку на функцию ПРЕДСТАВЛЕНИЕ() и перенос условных выражений в язык запросов сокращают время выгрузки в разы (в тестируемом примере — со 160 до 25-30 секунд).
Разберем эффективные приемы работы с файловыми объектами и строками во встроенном языке:
ТекстовыйДокумент на ЗаписьТекста. Объект ЗаписьТекста осуществляет потоковую буферизованную запись непосредственно в файл, исключая лишние накладные расходы на хранение документа в оперативной памяти.Символ() на каждой итерации:
СимволРазделитель = Символ(166);
ФайлНоменклатура = Новый ЗаписьТекста(ПутьКФайлу, КодировкаТекста.UTF8);
Пока Выборка.Следующий() Цикл
// Сборка строки с заранее объявленным разделителем
Стр = Выборка.ШтрихКод
+ СимволРазделитель + Выборка.НоменклатураПредставление
+ СимволРазделитель + Выборка.ПроизводительПредставление
+ СимволРазделитель + Формат(Выборка.РозничнаяЦенаВычисленная, "ЧГ=");
ФайлНоменклатура.ЗаписатьСтроку(Стр);
КонецЦикла;
ФайлНоменклатура.Закрыть();
Рассмотрим дополнительные техники платформы 1С для оптимизации выгрузки данных:
СтрСоединить()Чтобы избежать частой конкатенации подстрок, можно накапливать значения колонок в массиве и объединять их за один вызов функции СтрСоединить(). Это сводит к минимуму фрагментацию оперативной памяти:
СимволРазделитель = Символ(166);
МассивКолонок = Новый Массив;
Пока Выборка.Следующий() Цикл
МассивКолонок.Очистить();
МассивКолонок.Добавить(Выборка.ШтрихКод);
МассивКолонок.Добавить(Выборка.НоменклатураПредставление);
МассивКолонок.Добавить(Формат(Выборка.РозничнаяЦенаВычисленная, "ЧГ="));
Стр = СтрСоединить(МассивКолонок, СимволРазделитель);
ФайлНоменклатура.ЗаписатьСтроку(Стр);
КонецЦикла;
ТабличныйДокументПлатформа 1С содержит встроенный быстрый механизм сохранения табличных документов в формат CSV. Запись выполняется средствами ядра платформы C++ и обрабатывает данные быстрее обхода во встроенном языке:
ТабДок = Новый ТабличныйДокумент;
Построитель = Новый ПостроительОтчета;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(РезультатЗапроса);
Построитель.Вывести(ТабДок);
// Быстрая выгрузка нативным методом платформы
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.CSV);
При выгрузке сверхбольших объемов данных (миллионы строк) рекомендуется разделить выборку на интервалы (например, по коду или УИД) и запустить несколько фоновых заданий через объект ФоновыеЗадания. Каждое задание параллельно выгружает свою часть данных во временный файл, после чего итоговые файлы объединяются.
Применяя перенос вычислений в язык запросов и используя объект ЗаписьТекста, удается сократить время формирования файла в разы и обеспечить стабильную работу сервера.