Как ускорить поиск и обновление элементов справочника по артикулу в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Анализ проблемы и распространенных ошибок

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


// Неоптимальный код с ошибкой обхода
Спр = СоздатьОбъект("Справочник.Номенклатура");
Для х = 2 По КоличествоСтрок Цикл
    Артикул = СокрЛП(Строка(Excel.Cells(х, 1).Value));
    Штрихкод = СокрЛП(Строка(Excel.Cells(х, 2).Value));   
    Спр.ВыбратьЭлементы();
    Пока Спр.Выбран() = 1 Цикл // ОШИБКА: бесконечный цикл!
        Если СокрЛП(Спр.Артикул) = Артикул Тогда
            Спр.Штрихкод = Штрихкод;
            Спр.Записать(); 
        КонецЕсли;   
    КонецЦикла;
КонецЦикла;

В приведенном фрагменте присутствуют сразу два узких места:

  1. Критическая ошибка позиционирования: Метод Спр.Выбран() проверяет, выбран ли элемент в данный момент, но сам по себе не осуществляет переход к следующему элементу. Для позиционирования на следующей записи справочника необходимо использовать метод Спр.ПолучитьЭлемент().
  2. Алгоритмическая неэффективность: Полный перебор всего справочника на каждую строку файла (например, 500 строк Excel * 15 000 элементов справочника) дает 7,5 миллионов итераций, что вызывает зависание программы.

Решение 1: Использование метода ВыбратьЭлементыПоРеквизиту (Оптимальный способ)

Самый быстрый и штатный способ найти элементы по конкретному значению реквизита в 1С 7.7 — применение метода ВыбратьЭлементыПоРеквизиту(). Он позволяет платформе выполнять выборку с использованием индексов базы данных, не просматривая лишние записи.

Важное требование платформы: Данный метод работает только для тех реквизитов, у которых в Конфигураторе включено свойство «Сортировка» или «Отбор по реквизиту». В противном случае 1С выдаст ошибку выполнения.

Посмотрим на итоговый правильный и быстродействующий код:


Спр = СоздатьОбъект("Справочник.Номенклатура");
Для х = 2 По КоличествоСтрок Цикл
    Сообщить("Обрабатываем строку: " + х);
    Артикул = СокрЛП(Строка(Excel.Cells(х, 1).Value));
    Штрихкод = СокрЛП(Строка(Excel.Cells(х, 2).Value));   
    
    // Выбираем только те элементы, у которых Артикул совпадает с искомым
    Спр.ВыбратьЭлементыПоРеквизиту("Артикул", Артикул, 0, 0);
    Пока Спр.ПолучитьЭлемент() = 1 Цикл  
        Спр.Штрихкод = Штрихкод;
        Спр.Записать();    
    КонецЦикла;
КонецЦикла;

Данный подход сокращает время выполнения с десятков минут до нескольких секунд.

Решение 2: Предварительная выгрузка справочника в Таблицу Значений

Если по каким-то причинам включить сортировку/отбор для реквизита в Конфигураторе невозможно, выберем альтернативный вариант: загнать справочник в оперативную память через ТаблицаЗначений.

Проанализируем алгоритм:

  1. Создаем таблицу значений и заполняем ее ссылками и артикулами за один проход по справочнику.
  2. Сортируем таблицу значений по колонке Артикул.
  3. Для каждой строки Excel ищем совпадения в таблице значений с помощью метода НайтиСтроки() или позиционирования методом НайтиЗначение().

ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("Артикул");
ТЗ.НоваяКолонка("Элемент");

Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
    ТЗ.НоваяСтрока();
    ТЗ.Артикул = СокрЛП(Спр.Артикул);
    ТЗ.Элемент = Спр.ТекущийЭлемент();
КонецЦикла;

// Сортировка ускоряет поиск в памяти
ТЗ.Сортировать("Артикул");

// Далее при совпадении позиционируемся на объект и меняем реквизит
СпрОбъект = СоздатьОбъект("Справочник.Номенклатура");
// Поиск и обновление в цикле по Excel...

Особенности применения встроенного языка запросов в 1С 7.7

Попытка решить задачу обновления данных через встроенный «черный запрос» 1С 7.7 имеет важную специфику: запросы в 1С 7.7 работают только на чтение. Выполнить команду обновления данных непосредственно внутри запроса невозможно.

Если использовать запрос для поиска элементов, код будет выглядеть следующим образом:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(ПоискНоменклатуры)
|Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
|Артикул = Справочник.Номенклатура.Артикул;
|Группировка Номенклатура без групп;
|Условие(СокрЛП(Артикул) = ИскомыйАртикул);
|"//}}ЗАПРОС;

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        ЭлементНоменклатуры = Запрос.Номенклатура;
        // Для изменения необходимо позиционировать объект справочника
        Спр.НайтиЭлемент(ЭлементНоменклатуры);
        Спр.Штрихкод = Штрихкод;
        Спр.Записать();
    КонецЦикла;
КонецЕсли;

Запуск такого запроса на каждой итерации цикла Excel по производительности уступает методу ВыбратьЭлементыПоРеквизиту(), поэтому использование `ВыбратьЭлементыПоРеквизиту` остается наиболее предпочтительным.

Рекомендации по дополнительному ускорению

Чтобы заставить обработку работать с максимальной скоростью, учтем следующие моменты:

← На главную