В практике разработки на платформе 1С Предприятие 8 часто возникает задача обработки больших массивов информации. Представим реальный сценарий: внешняя обработка загружает «тяжелый» файл (например, объемом более 10 Гб с миллионом строк) по API от внешнего поставщика услуг. Первичный парсинг и формирование таблицы значений занимают около 30 минут. Разумеется, заставлять пользователя ждать столько времени при каждом открытии формы невозможно.
Стандартное решение с использованием системных функций ЗначениеВФайл и ЗначениеИзФайла работает слишком медленно. Чтение файла объемом в несколько сотен мегабайт, содержащего миллион строк, занимает около 70 секунд. Наша цель — сократить это время до заветных 10 секунд или даже быстрее. В этой статье мы подробно разберем, как решить эту задачу с помощью передовых механизмов платформы 1С.
Прежде чем перейти к решениям, выясним причину медленной работы стандартной сериализации. Функции ЗначениеВФайл и ЗначениеИзФайла переводят внутренние структуры 1С во внутренний текстовый формат (XML-подобную разметку). Процесс десериализации такого файла сильно нагружает центральный процессор операциями парсинга текста, выделения памяти под каждую ячейку таблицы и проверкой типов данных.
Если таблица содержит исключительно простые типы данных (строки, числа, даты) и не содержит ссылок на объекты базы данных, мы можем применить альтернативные высокоэффективные методы.
---
Это самый простой и лаконичный способ кэширования данных в оперативной памяти сервера, не требующий написания сложных алгоритмов сериализации. Платформа 1С берет все заботы по управлению кэшем на себя.
Разберем по шагам, как это реализовать:
На время сеанса. Также убедимся, что стоят флаги Сервер и Вызов сервера.Рассмотрим пример кода в общем модуле КэшДанныхПоставщиков:
Функция ПолучитьТаблицуГостиниц(ПутьКФайлу) Экспорт
// Данный код выполнится полностью только ОДИН раз за сеанс
// или пока кэш не будет принудительно сброшен платформой.
ТаблицаРезультат = ИнициализироватьТаблицуКолонок();
// Тут происходит длительное чтение файла (например, JSON или CSV)
// ... логика заполнения таблицы ...
Возврат ТаблицаРезультат;
КонецФункции
При первом обращении к функции КэшДанныхПоставщиков.ПолучитьТаблицуГостиниц() платформа выполнит весь алгоритм парсинга, который может занять длительное время. Однако при повторном вызове функции с тем же параметром ПутьКФайлу платформа мгновенно вернет готовую таблицу значений прямо из оперативной памяти сервера. Скорость загрузки составит 0 секунд!
Важное примечание: Этот способ идеален, если оперативной памяти на сервере 1С достаточно. В условиях дефицита памяти или при неблагоприятных факторах среда выполнения может автоматически вытеснить кэш на диск, что приведет к повторному чтению.
---
Если нам необходимо передавать таблицу значений между сеансами или сохранять её программно, разработчики часто используют объект ХранилищеЗначения, который помещается во Временное хранилище или Параметры сеанса.
По умолчанию ХранилищеЗначения сжимает передаваемые данные по алгоритму deflate. Для таблицы объемом в 1,3 миллиона строк процесс сжатия и последующей распаковки в оперативной памяти приводит к колоссальным потерям производительности процессора.
Проанализируем ситуацию: если мы храним данные локально в оперативной памяти сервера, нам не нужно экономить дисковое пространство за счет процессорного времени. Мы можем принудительно отключить сжатие данных при создании объекта.
Посмотрим на пример кода сохранения таблицы:
// Отключаем сжатие данных, передавая степень сжатия 0
ХранилищеБезСжатия = Новый ХранилищеЗначения(МояОгромнаяТЗ, Новый СжатиеДанных(0));
// Помещаем во временное хранилище, привязанное к форме
АдресХранилища = ПоместитьВоВременноеХранилище(ХранилищеБезСжатия, УникальныйИдентификатор);
При десериализации такого объекта из памяти платформа просто скопирует чистый бинарный дамп без выполнения математических расчетов по распаковке архива. Это сократит время извлечения данных в разы.
---
Давайте честно признаем: держать в оперативной памяти веб-клиента или даже тонкого клиента 1С таблицу из 1,3 миллиона строк — это критическая архитектурная ошибка. Пользователь физически не способен увидеть на экране монитора более 20–50 строк одновременно. Попытка загрузить всю ТЗ в форму приведет к зависанию интерфейса.
Правильный архитектурный подход заключается в нормализации данных и их хранении в базе данных программного комплекса.
Разберем по шагам правильную схему работы:
ВременныеДанныеПоставщиков). В качестве измерений добавляем ключевые поля (например, ИдентификаторОбъекта), а остальные колонки делаем ресурсами или реквизитами.Пример оптимизированной записи таблицы в Регистр Сведений:
НаборЗаписей = РегистрыСведений.ВременныеДанныеПоставщиков.СоздатьНаборЗаписей();
// Загружаем готовую таблицу напрямую в набор записей регистра
НаборЗаписей.Загрузить(МояОгромнаяТЗ);
// Записываем данные в транзакции базы данных
НаборЗаписей.Записать(Истина);
В форме обработки вместо гигантской таблицы значений мы настраиваем Динамический список с источником данных из нашего Регистра Сведений. Пользователь открывает форму мгновенно (за доли секунды). Платформа считывает из базы данных только те 30 строк, которые отображаются на экране. По мере прокрутки списка пользователем данные подгружаются незаметно и очень быстро.
---
Если вам все же необходимо передавать таблицу через файлы, стандартный XML или JSON парсинг можно заменить на использование бинарного XML (формат FastInfoset), который поддерживается платформой 1С из коробки.
Этот бинарный формат весит существенно меньше и обрабатывается на порядок быстрее обычного текстового сериализатора, так как не тратит время на преобразование текстовых строк в типы данных платформы.
Рассмотрим пример быстрой записи таблицы через ЗаписьFastInfoset:
ИмяФайла = ПолучитьИмяВременногоФайла("fi");
// Записываем данные ТЗ в бинарный поток XDTO
ЗаписьFI = Новый ЗаписьFastInfoset;
ЗаписьFI.ОткрытьФайл(ИмяФайла);
// Используем СериализаторXDTO для быстрой записи
СериализаторXDTO.ЗаписатьXML(ЗаписьFI, МояОгромнаяТЗ);
ЗаписьFI.Закрыть();
Для мгновенного восстановления таблицы значений используем обратный метод чтения:
ЧтениеFI = Новый ЧтениеFastInfoset;
ЧтениеFI.ОткрытьФайл(ИмяФайла);
// Восстанавливаем объект ТаблицаЗначений за секунды
МояОгромнаяТЗ = СериализаторXDTO.ПрочитатьXML(ЧтениеFI);
ЧтениеFI.Закрыть();
Такой подход позволяет обойти узкое горлышко дисковой подсистемы и парсинга, сокращая время восстановления таблицы до считанных секунд.
---
Рассмотрим очень интересный, оригинальный и неочевидный лайфхак. Он основан на том, что платформа преобразует ячейки табличного документа в таблицу значений силами скомпилированного низкоуровневого C++ кода, минуя медленный интерпретатор встроенного языка 1С.
Если сохранить данные в формате табличного документа 1С (файлы .mxl), мы можем использовать объект ПостроительЗапроса для моментального разбора структуры.
Разберем пример кода чтения:
ТабДок = Новый ТабличныйДокумент;
// Чтение MXL файла происходит платформой на C++
ТабДок.Прочитать(ПутьКФайлуMXL);
// Передаем область табличного документа в источник данных построителя запроса
ПЗ = Новый ПостроительЗапроса;
ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабДок.Область());
ПЗ.ЗаполнитьНастройки();
ПЗ.Выполнить();
// Выгружаем результат в чистую Таблицу Значений
МояОгромнаяТЗ = ПЗ.Результат.Выгрузить();
Этот метод показывает феноменальные результаты скорости выполнения на миллионных массивах строк, значительно превосходя классический обход файла в цикле.
---
Мы проанализировали несколько эффективных сценариев ускорения загрузки данных на сервере 1С. Выбор конкретного метода зависит от технических условий вашего проекта: