При работе с большими объемами данных в 1С:Предприятие программисты часто сталкиваются с проблемой производительности при формировании текстовых файлов. Задача выгрузки 2 миллионов строк может занимать часы, если использовать стандартные методы конкатенации строк. В этой статье мы разберем, почему так происходит, и проанализируем наиболее эффективные способы ускорения этого процесса — от оптимизации кода 1С до использования инструментов SQL-сервера.
Рассмотрим ситуацию, когда разработчик пытается собрать огромную строку в одной переменной, используя оператор "+". При каждом сложении строк Текст = Текст + НоваяСтрока система выделяет новый блок памяти для хранения результата. Когда объем переменной Текст достигает сотен мегабайт, операционная система тратит колоссальное время на перераспределение памяти и копирование данных. Именно поэтому первые 100 000 строк могут выгрузиться быстро, а скорость последующих падает в геометрической прогрессии.
Для решения этой задачи нам нужно исключить накопление данных в одной строковой переменной и перейти к потоковой записи или использованию специализированных функций сборки строк.
Самый правильный и эффективный способ работы с файлами в 1С — это использование объекта ЗаписьТекста. Этот объект выполняет буферизированную запись напрямую на диск, не перегружая оперативную память сервера или клиента огромными строковыми переменными.
Разберем пример оптимизированного кода, где мы также заменим медленную функцию Формат() на более быструю XMLСтрока() для простых преобразований типов:
РезультатЗапроса = Запрос.Выполнить();
ИменаПолей = Новый Массив;
Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл
ИменаПолей.Добавить(Колонка.Имя);
КонецЦикла;
ЗаписьТекста = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
// Записываем заголовок CSV
ЗаписьТекста.ЗаписатьСтроку("SL code|SKU code|Quantity|Year|Month|Day");
ВыборкаРезультат = РезультатЗапроса.Выбрать();
Пока ВыборкаРезультат.Следующий() Цикл
ЗначенияПолей = Новый Массив;
Для Каждого ИмяПоля Из ИменаПолей Цикл
// XMLСтрока работает быстрее, чем Формат для простых чисел и дат
ЗначенияПолей.Добавить(XMLСтрока(ВыборкаРезультат[ИмяПоля]));
КонецЦикла;
// СтрСоединить собирает строку из массива за один проход по памяти
ЗаписьТекста.ЗаписатьСтроку(СтрСоединить(ЗначенияПолей, "|"));
КонецЦикла;
ЗаписьТекста.Закрыть();
В этом примере мы используем СтрСоединить() для объединения полей текущей строки. Это гораздо быстрее, чем последовательное сложение через "+", так как система заранее знает длину итоговой строки строки и выделяет память однократно.
Если структура CSV-файла жестко задана и количество колонок не меняется, можно использовать функцию СтрШаблон(). Она позволяет подставлять значения в подготовленную маску, что читабельнее и зачастую быстрее ручной сборки строки.
Проанализируем пример использования шаблона внутри цикла:
Пока ВыборкаРезультат.Следующий() Цикл
СтрокаДляЗаписи = СтрШаблон("%1|%2|%3|%4|%5|%6",
ВыборкаРезультат.СкладID,
ВыборкаРезультат.НоменклатураID,
Формат(ВыборкаРезультат.Остаток, "ЧГ=0"),
Формат(ВыборкаРезультат.ГОД, "ЧГ=0"),
ВыборкаРезультат.МЕСЯЦ,
ВыборкаРезультат.ДЕНЬ);
ЗаписьТекста.ЗаписатьСтроку(СтрокаДляЗаписи);
КонецЦикла;
Если запись каждой отдельной строки через ЗаписьТекста.ЗаписатьСтроку() все еще кажется медленной (например, из-за медленной дисковой подсистемы), можно применить метод накопления данных в массиве и записи "пачками". Выясним, как это реализовать:
СтрСоединить(Массив, Символы.ПС) и записываем один большой блок данных методом ЗаписьТекста.Записать().Это сокращает количество обращений к API операционной системы для записи на диск, что может дать существенный прирост на высоконагруженных серверах.
Если база данных работает на MS SQL Server, и вам требуется максимальная скорость (выгрузка 2 млн строк за секунды, а не минуты), стоит рассмотреть возможность обхода объектной модели 1С. Рассмотрим два варианта:
1. Использование утилиты BCP (Bulk Copy Program)
Это системная утилита SQL Server, предназначенная специально для массового импорта/экспорта данных. Вы можете сформировать SQL-представление (View) или временную таблицу с нужными данными, а затем вызвать bcp.exe через команду ЗапуститьПриложение(). Это самый быстрый из существующих способов.
2. Выгрузка через ADODB.Connection
Вы можете подключиться к базе данных напрямую через COM-объект ADODB, выполнить SQL-запрос и сохранить результат. Некоторые драйверы позволяют сохранять Recordset напрямую в CSV.
// Пример логики прямого обращения (упрощенно)
Connection = Новый COMОбъект("ADODB.Connection");
Connection.Open(СтрокаПодключенияКSQL);
Recordset = Connection.Execute("SELECT СкладID, НоменклатураID, Остаток FROM dbo._InfoRg12345");
// Далее следует потоковая запись данных из Recordset в файл
Чтобы процесс выгрузки прошел максимально гладко, рекомендуем обратить внимание на следующие технические аспекты:
copy /b file1+file2 result.csv.Подведем итог: для большинства задач в 1С достаточно перехода на ЗаписьТекста в сочетании с СтрСоединить и отказом от избыточных вызовов Формат(). Если же требования к скорости критичны, единственным верным путем будет использование инструментов прямого доступа к СУБД, таких как BCP.