Как ускорить поиск данных в результате запроса при выгрузке в Excel и избежать ошибок сопоставления

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке обработок выгрузки данных из 1С в существующие шаблоны Excel программисты часто сталкиваются с проблемой производительности. Когда порядок строк в файле заказчика не совпадает с порядком в базе данных, возникает необходимость искать соответствие для каждой строки. Если делать это «в лоб» через перебор результата запроса, время выполнения операции растет в геометрической прогрессии. Разберем, как оптимизировать этот процесс и почему стандартный поиск может выдавать ошибку даже при видимом совпадении данных.

Анализ проблемы производительности

Рассмотрим ситуацию: у нас есть результат запроса и открытый лист Excel. Нам нужно для каждой строки Excel найти соответствующий код номенклатуры в данных 1С и заполнить колонки с остатками и продажами. Типичная ошибка — использование вложенного цикла или метода НайтиСледующий() прямо в процессе обхода строк файла. Проанализируем, почему это медленно:

  1. Сложность алгоритма: Если в Excel 1000 строк и в результате запроса 1000 строк, то при полном переборе система выполнит до 1 000 000 итераций.
  2. Работа курсора: Метод НайтиСледующий() перемещает курсор выборки. После того как курсор дойдет до конца, его нужно каждый раз возвращать в начало методом Сбросить(), что создает колоссальную нагрузку на ресурсы.
  3. COM-соединение: Обращение к каждой ячейке через Cells(Ячейка, Колонка).Value само по себе является медленной операцией из-за взаимодействия между процессами 1С и Excel.

Решение №1: Использование индексированной Таблицы Значений

Самый простой и эффективный способ ускорить поиск — выгрузить результат запроса в объект ТаблицаЗначений и проиндексировать колонку, по которой осуществляется поиск (например, «Код»). Индексация создает в памяти хеш-таблицу, которая позволяет находить нужную строку практически мгновенно, минуя полный перебор.

Рассмотрим пример кода для реализации этого метода:


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

// 2. Индексируем колонку для быстрого поиска
ТаблицаРезультата.Индексы.Добавить("Код");

// 3. Обходим строки Excel
Для Ячейка = НачальнаяСтрока По КонечнаяСтрока Цикл
    КодИзExcel = Формат(лист.Cells(Ячейка, 2).Value, "ЧЦ=11; ЧВН=; ЧГ=0");
    
    // Используем метод Найти(), который работает мгновенно по индексу
    НайденнаяСтрока = ТаблицаРезультата.Найти(КодИзExcel, "Код");
    
    Если НайденнаяСтрока <> Неопределено Тогда
        // Заполняем данные в Excel
        лист.Cells(Ячейка, 5).Value = НайденнаяСтрока.КолВоНаСклдахНачалоПериода;
        лист.Cells(Ячейка, 6).Value = НайденнаяСтрока.КолВоНаПроизводствеНачалоПериода;
        // ... заполнение остальных полей
    КонецЕсли;
КонецЦикла;

Решение №2: Использование объекта Соответствие (Map)

Если вам нужна максимальная скорость поиска в памяти, проанализируем использование объекта Соответствие. В 1С этот объект реализован как ассоциативный массив, где поиск по ключу происходит быстрее, чем поиск в таблице значений, так как не требует работы с индексами всей таблицы.

Разберем по шагам, как это применить:

  1. Выгружаем результат запроса в таблицу.
  2. Создаем объект Соответствие.
  3. Одним циклом заполняем его, где ключом будет Код, а значением — Строка таблицы.

КешДанных = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    КешДанных.Вставить(Выборка.Код, Выборка);
КонецЦикла;

// Теперь в цикле по Excel поиск будет выглядеть так:
НайденныеДанные = КешДанных.Получить(КодИзExcel);
Если НайденныеДанные <> Неопределено Тогда
    // Обработка данных
КонецЕсли;

Выясним причину ошибок сопоставления («Ложь» при поиске)

Часто программисты сталкиваются с тем, что визуально коды в 1С и Excel одинаковы, но 1С их «не видит». Проанализируем основные причины:

Продвинутый метод: Выгрузка через массив

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

Посмотрим на пример логики:

  1. Считываем все коды из колонки Excel в массив 1С за один раз.
  2. Проводим сопоставление в памяти 1С.
  3. Формируем массив результатов.
  4. Записываем массив результатов обратно в диапазон Excel.

Этот подход сокращает время работы с файлом в 10–50 раз, так как основная задержка обычно вызвана именно «пингом» между 1С и приложением Excel.

Важный момент: При использовании метода НайтиСледующий() в цикле, не забывайте, что он ищет от текущей позиции курсора. Если вы ищете значения, которые в результате запроса идут «выше» текущей строки, вы их не найдете без вызова Сбросить(). Именно поэтому использование индексированной ТаблицыЗначений является «золотым стандартом» для решения подобных задач.

← На главную