Почему 1С медленно загружает данные из Excel и как многократно ускорить этот процесс?

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

Многие разработчики сталкиваются с тем, что после обновления платформы 1С:Предприятие (например, до версии 8.3.20 и выше) загрузка объемных данных из файлов Excel начинает работать катастрофически медленно. Процесс, который ранее занимал приемлемое время, может растянуться на много часов. Давайте проанализируем ситуацию, выясним причину такого поведения платформы и разберем по шагам, как кардинально ускорить получение данных из таблиц.

Почему классический перебор ячеек сильно тормозит?

Обычно в устаревшем коде загрузки используется построчный перебор ячеек в цикле, где данные читаются конструкцией вида Лист.Cells(Строка, Колонка).Value. Проблема заключается в том, что при каждом таком вызове 1С совершает отдельное обращение через границу процессов к приложению MS Excel.

В новых версиях платформы 1С и новых версиях операционных систем Windows механизмы безопасности и внутренней архитектуры изменились, из-за чего кросс-процессные COM-вызовы стали обходиться операционной системе намного "дороже" по времени. Если в файле десятки тысяч строк и множество колонок, 1С выполняет миллионы независимых обращений к Excel, что и приводит к зависаниям на несколько часов.

Решение 1: Чтение целого блока данных через Range и COMSafeArray

Рассмотрим подробнее самый правильный и быстрый подход при работе через COM-соединение. Чтобы избавиться от архитектурной проблемы медленного соединения, нам нужно сделать всего одно обращение к Excel, забрать сразу все данные и затем обрабатывать их уже внутри оперативной памяти 1С.

Для этого мы обратимся к свойству Value у объекта Range. В этом случае Excel сформирует и вернет специальный объект COMSafeArray. В свою очередь, платформа 1С умеет мгновенно конвертировать его в привычный многомерный массив с помощью встроенного метода Выгрузить().

Посмотрим на пример кода, который позволил сократить время чтения с 7 часов до 11 минут:


КоличествоЛистов = Книга.Sheets.Count;
Лист = Книга.Sheets(1);

// Получаем границы заполненных данных
ВсегоКолонок = Лист.Cells(1,1).SpecialCells(11).Column;
ВсегоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;    
    
// Выделяем всю заполненную область
Область = Лист.Range(Лист.Cells(1,1), Лист.Cells(ВсегоСтрок, ВсегоКолонок));

// Совершаем одно обращение к Excel и выгружаем данные в многомерный массив 1С
Данные = Область.Value.Выгрузить();

// Теперь переменная "Данные" содержит двумерный массив 1С
// Перебор массива работает моментально:
Для ИндексСтроки = 0 По Данные.ВГраница() Цикл
    // Читаем значения массива
    КоличествоПродНЕОБР = Данные[ИндексСтроки][КолонкаКоличествоПродажа];
    // ... дальнейшая логика
КонецЦикла;

При таком подходе мы полностью исключаем постоянные дерганья Excel в цикле, и все вычисления происходят исключительно на стороне 1С.

Решение 2: Использование технологии ADO

Другим классическим способом ускорения является чтение файла средствами Microsoft ADO. Этот метод рассматривает файл Excel как базу данных и позволяет обращаться к листам с помощью SQL-запросов.

Однако при использовании драйверов ADODB необходимо учитывать подводные камни:

  1. ADO анализирует первые строки колонки, чтобы автоматически определить тип данных. Если сверху идут числа (например, артикулы из одних цифр), а ниже встречается текст с буквами, ADO может вернуть пустую строку Null, посчитав текст ошибкой формата.
  2. Возможны сбои, если разрядность сервера 1С (например, 64-бит) не совпадает с разрядностью установленных драйверов MS Office (32-бит).
  3. Для быстрой работы лучше использовать метод GetRows() для получения массива записей, вместо перебора объекта Recordset в цикле.

Решение 3: Оптимизация чтения через Табличный документ (Построитель запроса)

Часто разработчики пытаются уйти от COM-объектов, используя штатный метод платформы ТабличныйДокумент.Прочитать(ПутьКФайлу). Но если затем обходить документ циклами ТабДок.Область(R, C).Текст, это тоже работает недостаточно быстро.

Разберем обходной маневр, который позволяет быстро преобразовать прочитанный табличный документ в удобную для работы таблицу значений без циклов:


ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);

Построитель = Новый ПостроительЗапроса;
// Передаем область загруженного документа в качестве источника данных
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабДок.Область());
Построитель.Выполнить();

// Выгружаем результат напрямую в Таблицу Значений
ТаблицаИзExcel = Построитель.Результат.Выгрузить();

Этот метод работает исключительно силами платформы 1С, не требует установки MS Office на сервере и отлично подходит для кроссплатформенных сред (например, при работе серверов 1С на ОС Linux).

Решение 4: Нативное чтение (NativeXLSX) и парсинг XML

Самым современным подходом, который сейчас активно внедряется в типовых конфигурациях 1С, является полный отказ от внешних приложений (COM) и драйверов. Дело в том, что файлы формата .xlsx представляют собой обычные ZIP-архивы, внутри которых структура документа описана в виде XML-файлов.

Нативное чтение подразумевает распаковку этого архива средствами 1С (объект ЧтениеZipФайла) и прямой парсинг XML (с помощью ЧтениеXML или ПостроительDOM).

Это самый отказоустойчивый метод для загрузки гигантских прайс-листов. Он полностью страхует систему от ситуаций, когда на сервере зависают невидимые фоновые экземпляры Excel.Application, которые постепенно съедают всю оперативную память.

Подведем итог: если вам необходимо быстро оптимизировать старую обработку загрузки, работающую через COM, используйте чтение всего листа в COMSafeArray. Если же вы разрабатываете новый надежный функционал обмена для высоконагруженной базы — отдавайте предпочтение чтению через табличный документ или нативному разбору XML-структуры XLSX-файла.

← На главную