Как эффективно загрузить данные из Excel в табличное поле и оптимизировать поиск ссылок по наименованию?

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

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

Проблема использования метода НайтиПоНаименованию() в цикле

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

Почему это плохо? Каждый вызов этого метода инициирует отдельное обращение к серверу базы данных. Представим, что само выполнение поиска занимает доли секунды, но накладные расходы на установку соединения и передачу данных (latency) суммируются. Если строк 700, мы получим 700 обращений. Кроме того, этот метод возвращает первый попавшийся элемент, который может оказаться помеченным на удаление или быть группой, что в контексте загрузки данных часто является ошибкой.

Решение 1: Использование запроса с условием "В (&Массив)"

Для оптимизации процесса мы можем собрать все уникальные наименования из файла Excel в один массив и передать его в запрос. Это позволит получить все необходимые ссылки за одно обращение к базе данных. Проанализируем, как это реализовать:

  1. Прочитаем данные из Excel и заполним массив наименований.
  2. Создадим запрос к нужному справочнику.
  3. Установим условие отбора по наименованию из массива.
  4. Выгрузим результат запроса во временную таблицу значений или соответствие для быстрого поиска в памяти.

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


// 1. Формируем массив наименований из данных Excel
МассивНаименований = Новый Массив;
Для Каждого СтрокаДанных Из ДанныеExcel Цикл
    МассивНаименований.Добавить(СокрЛП(СтрокаДанных.Наименование));
КонецЦикла;

// 2. Выполняем запрос для получения ссылок
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Наименование КАК Наименование,
    |	Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Наименование В (&МассивНаименований)
    |	И НЕ Номенклатура.ПометкаУдаления
    |	И НЕ Номенклатура.ЭтоГруппа";

Запрос.УстановитьПараметр("МассивНаименований", МассивНаименований);
ТаблицаСсылок = Запрос.Выполнить().Выгрузить();

// 3. Используем таблицу для сопоставления
Для Каждого СтрокаДанных Из ДанныеExcel Цикл
    ПараметрыОтбора = Новый Структура("Наименование", СокрЛП(СтрокаДанных.Наименование));
    НайденныеСтроки = ТаблицаСсылок.НайтиСтроки(ПараметрыОтбора);
    Если НайденныеСтроки.Количество() > 0 Тогда
        СтрокаТП.Номенклатура = НайденныеСтроки[0].Ссылка;
    КонецЕсли;
КонецЦикла;

Решение 2: Использование Временных Таблиц (ВТ)

Если объем данных велик (несколько тысяч строк и более), использование массива в условии ГДЕ ... В может привести к деградации производительности СУБД. В таких случаях эффективнее передать всю таблицу данных из Excel во временную таблицу запроса. Это позволит выполнить внутреннее соединение на уровне сервера БД, что является максимально быстрым способом сопоставления.

Разберем алгоритм работы с ВТ:

  1. Создаем ТаблицуЗначений с колонкой "Наименование" и загружаем в неё данные.
  2. Передаем эту таблицу в менеджер временных таблиц запроса.
  3. В тексте запроса соединяем ВТ со справочником по полю "Наименование".

Важный совет: При использовании временных таблиц всегда индексируйте поля, по которым происходит соединение. Это критически важно для скорости работы запроса.

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

В процессе разработки загрузки часто возникает необходимость ограничить поиск только определенной папкой (группой) справочника. Рассмотрим типичную ошибку, когда отбор В ИЕРАРХИИ не срабатывает. Выясним причину: часто программный поиск группы по коду или наименованию возвращает ПустаяСсылка, если объект не найден, и последующий запрос просто не находит данных.

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


ГруппаСтатей = Справочники.СтатьиДвиженияДенежныхСредств.НайтиПоКоду("001");

Если ГруппаСтатей.Пустая() Тогда
    Сообщить("Группа с кодом 001 не найдена!");
    Возврат;
КонецЕсли;

Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ГруппаСтатей", ГруппаСтатей);
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Статьи.Ссылка КАК Ссылка,
    |	Статьи.Наименование КАК Наименование
    |ИЗ
    |	Справочник.СтатьиДвиженияДенежныхСредств КАК Статьи
    |ГДЕ
    |	Статьи.Ссылка В ИЕРАРХИИ(&ГруппаСтатей)
    |	И Статьи.ЭтоГруппа = ЛОЖЬ";

// Если используется пакет запросов, обрабатываем результат через ВыполнитьПакет()
МассивРезультатов = Запрос.ВыполнитьПакет();
Выборка = МассивРезультатов[0].Выбрать();

Пока Выборка.Следующий() Цикл
    // Обработка данных
КонецЦикла;

Очистка данных и борьба с "невидимыми" символами

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

Подведение итогов

Для качественной загрузки данных из Excel мы рекомендуем:

  1. Минимизировать количество обращений к БД: Используйте один запрос для получения всех необходимых ссылок вместо поиска в цикле.
  2. Фильтровать результат: В запросе всегда добавляйте условия НЕ ПометкаУдаления и НЕ ЭтоГруппа, чтобы избежать получения некорректных ссылок.
  3. Контролировать пакеты: При использовании ВыполнитьПакет() убедитесь, что вы обходите все результаты и используете метод Следующий() для выборки данных.
  4. Кэшировать данные: Для небольших справочников загрузка всех элементов в объект Соответствие (где Ключ — Наименование, а Значение — Ссылка) обеспечит мгновенный поиск без повторных обращений к серверу.

Использование этих подходов не только ускорит загрузку в десятки раз, но и сделает ваш код более надежным и устойчивым к ошибкам в данных.

← На главную