Как оптимизировать загрузку цен номенклатуры в 1С при больших объемах данных?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Прежде всего, проанализируем ситуацию с типовым документом Установка цен номенклатуры. В большинстве конфигураций 1С (УТ 11, ERP, КА) форма этого документа перегружена логикой: при добавлении строк происходят пересчеты, проверки, форматирование и отображение представлений. Если в табличную часть попытаться загрузить 100 000 строк и более, клиентское приложение может «зависнуть» на десятки минут. Более того, существует технологическое ограничение на количество строк в табличной части (обычно до 100 000 для комфортной работы), после которого работа с документом в интерфейсе становится невозможной.

Для решения этой проблемы рассмотрим несколько эффективных подходов.

Решение 1. Использование временных таблиц в запросах

Это классический и наиболее рекомендуемый способ. Вместо того чтобы искать каждую номенклатуру в цикле методом НайтиПоРеквизиту, мы должны перенести всю тяжесть поиска на SQL-сервер. Разберем по шагам, как это реализовать:

  1. Сначала прочитаем данные из файла в таблицу значений (ТЗ). Важно использовать максимально быстрые способы чтения (например, ЧтениеТекста для CSV-файлов вместо COM-объекта Excel).
  2. Поместим ТЗ во временную таблицу в запросе.
  3. Выполним соединение временной таблицы со справочником Номенклатура по полю Артикул.

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


// Создаем таблицу значений с данными из файла
ТЗДанныеФайла = Новый ТаблицаЗначений;
ТЗДанныеФайла.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(50)));
ТЗДанныеФайла.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));

// ... (здесь идет код заполнения ТЗ из файла) ...

МенеджерВТ = Новый МенеджерВременных Таблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

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

Запрос.УстановитьПараметр("ТЗДанныеФайла", ТЗДанныеФайла);
РезультатЗапроса = Запрос.Выполнить();

Важный нюанс: Если в файле могут быть дубли артикулов или в справочнике одному артикулу соответствует несколько позиций, запрос вернет избыточные данные. Проанализируем ситуацию: для корректной работы следует использовать ВЫБРАТЬ РАЗЛИЧНЫЕ или предварительно сворачивать ТЗ.

Решение 2. Использование объекта «Соответствие» (Кэширование в памяти)

Если справочник Номенклатура не меняется в процессе загрузки, мы можем один раз прочитать все необходимые данные в оперативную память. Поиск по объекту Соответствие или Структура в 1С происходит мгновенно (используется хеш-таблица).

Разберем алгоритм:

  1. Запросом выбираем из базы данных все связки Артикул -> Ссылка.
  2. Загружаем их в Соответствие, где ключом будет артикул.
  3. При чтении файла просто получаем ссылку из соответствия по ключу-артикулу.

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

Пока Выборка.Следующий() Цикл
    // Если артикулы дублируются, логика может быть сложнее (например, хранить массив ссылок)
    КартаНоменклатуры.Вставить(СокращенныйЛП(Выборка.Артикул), Выборка.Ссылка);
КонецЦикла;

// Теперь при обходе файла поиск будет мгновенным
СсылкаНаТовар = КартаНоменклатуры.Получить(АртикулИзФайла);
Если СсылкаНаТовар <> Неопределено Тогда
    // Заполняем данные
КонецЕсли;

Этот метод потребляет значительный объем оперативной памяти (для 200 000 ссылок потребуется несколько сотен мегабайт), поэтому его рекомендуется выполнять на 64-битном сервере приложений.

Решение 3. Обход ограничений интерфейса и запись в регистр

Когда мы нашли ссылки на номенклатуру, встает вопрос записи. Как мы выяснили, 500 000 строк в один документ Установка цен номенклатуры записывать нельзя. Рассмотрим способы обхода:

  1. Дробление на порции: Создавайте несколько документов, например, по 50 000 или 90 000 строк в каждом. Это позволит системе стабильно записывать и проводить документы без блокировок и переполнения памяти.
  2. Отключение проверок: При записи программно созданного документа используйте режим ОбменДанными.Загрузка = Истина. Это отключит лишние проверки в модуле объекта и ускорит запись в разы.
  3. Прямая запись в Регистр Сведений: Если регламент компании позволяет, можно записывать данные напрямую в регистр сведений ЦеныНоменклатуры (или аналогичный), минуя документ. Однако помните, что в этом случае вы теряете историю (кто и когда создал документ) и возможность типового пересчета цен.

Технические советы по оптимизации

Выясним дополнительные факторы, которые влияют на скорость загрузки:

Индексация: Проверьте в конфигураторе, стоит ли у реквизита Артикул свойство "Индексировать". Без индекса поиск по 200-тысячному справочнику будет медленным вне зависимости от выбранного метода программирования.

Фоновые задания: Если сервер имеет много ядер, процесс обработки файла можно распараллелить. Разделите файл на 4-5 частей и запустите обработку каждой части в отдельном фоновом задании. Главное — следите за тем, чтобы разные потоки не пытались одновременно записывать данные в один и тот же регистр с пересекающимися измерениями, чтобы избежать блокировок SQL.

Чтение данных: Использование ЧтениеТекста для CSV/TXT файлов работает на порядок быстрее, чем Excel.Application. Если поставщик присылает XLSX, рассмотрите возможность использования внешних компонент для быстрого чтения Excel без установленного офиса.

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

← На главную