Многие разработчики 1С при переходе на новые релизы платформы (начиная с 8.3.15 и выше) столкнулись с неприятной особенностью: привычная операция сохранения отчета в формат Excel стала занимать в 2–3 раза больше времени, чем на старых версиях (например, на 8.3.12). Когда речь идет о формировании реестров на десятки тысяч строк, ожидание превращается в критическую проблему для пользователей.
В этой статье мы подробно проанализируем, почему это происходит, разберем результаты тестов и рассмотрим все доступные способы решения проблемы — от простых настроек до использования внешних инструментов.
Рассмотрим ситуацию на конкретном примере. Представим типовую задачу: сохранение печатной формы акта, состоящей из шапки, таблицы на 16 000 строк (5 колонок) и подвала. Мы выполним операцию 10 раз и замерим среднее время выполнения метода Записать() в контексте серверного вызова.
Результаты замеров показывают следующую картину:
Разберем, почему штатный метод ТабличныйДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX) стал работать медленнее. Основная причина кроется в глубокой переработке внутреннего движка платформы. Начиная с версии 8.3.15, компания «1С» изменила алгоритмы формирования структуры OpenXML. Новый механизм стал более строго следовать спецификациям формата, что повлекло за собой огромные накладные расходы на сериализацию данных и управление временными файлами.
Проанализируем структуру XLSX. Это, по сути, ZIP-архив, внутри которого лежат XML-файлы. В новых версиях платформы процесс «сборки» этого архива стал крайне чувствителен к количеству уникальных стилей в документе. Если в вашем отчете каждая вторая строка имеет индивидуальную границу или шрифт, платформа тратит колоссальное время на проверку и регистрацию этих стилей в общем реестре файла. На старых платформах этот процесс был менее строгим и более линейным.
Выясним, как платформа ведет себя на дисковом уровне. При записи больших документов версии 8.3.16+ создают огромное количество мелких временных файлов в папке %TEMP%. Если на сервере включен антивирус или дисковая подсистема перегружена, каждое обращение к кэшу замедляет общий процесс. Старые версии платформы старались держать больше данных в оперативной памяти, что было быстрее.
Самый простой, но не всегда доступный путь — это обновление. Проблема была частично признана разработчиками 1С и оптимизирована в более поздних ветках. Если ваша конфигурация позволяет, рассмотрите переход на релизы 8.3.18.1300 и выше, либо на актуальные версии 8.3.22/8.3.23. В них механизм формирования XML был пересмотрен, и скорость сохранения в XLSX в некоторых случаях вернулась к показателям 8.3.12.
Если обновление платформы невозможно, попробуем обходной путь через формат ODS. Практика показывает, что на «проблемных» платформах (16 и 17 релизы) сохранение в формат OpenDocument Spreadsheet происходит значительно быстрее, чем в XLSX. Современный Microsoft Excel прекрасно открывает файлы .ods без потери данных и оформления.
Посмотрим на пример кода для реализации этого подхода:
// Вместо сохранения напрямую в XLSX
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.ODS);
Важный момент: проверьте, не используют ли ваши пользователи макросы в Excel, которые жестко завязаны на расширение .xlsx. Если нет — это самый дешевый способ ускорить выгрузку.
Для максимально высокой скорости (в 10–50 раз быстрее штатных средств) мы можем использовать внешние компоненты, которые работают с XLSX напрямую через библиотеки на C++ (например, LibXL) или C# (ClosedXML, EPPlus). В этом случае мы не используем ТабличныйДокумент как промежуточное звено для сохранения, а пишем данные сразу из таблицы значений или результата запроса.
Рассмотрим логику работы такой компоненты:
ТаблицаЗначений.Этот метод требует программирования, но он незаменим, когда отчеты содержат сотни тысяч строк.
Рассмотрим классический вариант через Excel.Application. Несмотря на то что автор темы искал альтернативы этому методу, в условиях медленной работы платформенного метода Записать(), COM-объект может оказаться быстрее, так как он использует родные алгоритмы Microsoft Excel для формирования файла.
Разберем пример кода для выгрузки:
Попытка
Эксель = Новый COMОбъект("Excel.Application");
Книга = Эксель.Workbooks.Add();
Лист = Книга.Worksheets(1);
// Перенос данных из ТабличногоДокумента через буфер обмена
// или по ячейкам (поячеечно будет медленно!)
ТабДок.Копировать();
Лист.Paste();
Книга.SaveAs(ИмяФайла);
Эксель.Quit();
Исключение
Сообщить("Ошибка при работе с Excel: " + ОписаниеОшибки());
КонецПопытки;
Внимание: данный метод требует установленного Microsoft Excel на сервере или клиенте (в зависимости от контекста выполнения), что не всегда возможно в Linux-инфраструктуре или на нагруженных серверах приложений.
Если мы вынуждены использовать штатный метод Записать(), проанализируем ситуацию и попробуем упростить сам документ. Выясним, какие элементы оформления замедляют процесс сильнее всего:
Попробуем программно минимизировать оформление перед записью:
// Пример упрощения оформления для ускорения записи
Для Каждого Область Из ТабДок.Области Цикл
// Оставляем только важные границы, убираем сложные стили
Область.ЦветФона = ЦветаСтиля.Белый;
КонецЦикла;
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
Проблема замедления выгрузки в Excel в версиях 8.3.16 и 8.3.17 является архитектурной особенностью данных релизов. Чтобы вернуть комфортную скорость работы пользователям, мы рекомендуем:
Выбор метода зависит от ваших технических условий и возможности обновления системного ПО.