При пакетной загрузке данных, например при импорте нескольких тысяч или десятков тысяч штрихкодов номенклатуры в конфигурации «1С:Розница» или «1С:Управление торговлей», разработчики часто сталкиваются с крайне низкой производительностью. Запись относительно небольшого объема данных (10 000 строк) стандартным перебором через объект РегистрСведенийМенеджерЗаписи может занимать до часа и более. Рассмотрим подробно, почему возникает эта проблема, какие ограничения платформы 1С необходимо учитывать и как правильно оптимизировать процесс массовой записи.
Проанализируем основные факторы, замедляющие запись в регистр сведений при использовании построчного менеджера записи:
МенеджерЗаписи.Записать() платформа открывает и фиксирует отдельную транзакцию на уровне СУБД для каждой отдельной строки. Для 10 000 записей это означает 10 000 физических обращений к журналу транзакций дисковой подсистемы, что создает критическую нагрузку на ввод-вывод.Разберем важные платформенные особенности, которые влияют на выбор алгоритма оптимизации:
РегистрСведенийНаборЗаписей свойство Отбор поддерживает исключительно вид сравнения Равно. Передать массив или список значений номенклатуры в отбор набора записей платформенно невозможно.Попытка ... Исключение), транзакция на уровне СУБД автоматически помечается как недействительная. Вызов метода ЗафиксироватьТранзакцию() после этого приведет к аварийному падению с ошибкой «Транзакция уже отменена». Поэтому вся транзакция целиком должна обрамляться блоком попытки.Перед записью данных в регистр необходимо отсечь внутренние дубликаты штрихкодов в исходной таблице и проверить их наличие в базе, чтобы избежать системных исключений нарушения уникальности записей СУБД. Посмотрим на пример проверки через временную таблицу:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ТШК.Штрихкод КАК Штрихкод,
| ТШК.Номенклатура КАК Номенклатура,
| ТШК.Характеристика КАК Характеристика
|ПОМЕСТИТЬ ВТ_ИсходныеШК
|ИЗ
| &ТаблицаШтрихкодов КАК ТШК
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ВТ.Штрихкод КАК Штрихкод,
| ВТ.Номенклатура КАК Номенклатура,
| ВТ.Характеристика КАК Характеристика
|ИЗ
| ВТ_ИсходныеШК КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК РСШК
| ПО ВТ.Штрихкод = РСШК.Штрихкод
|ГДЕ
| РСШК.Штрихкод ЕСТЬ NULL";
Запрос.УстановитьПараметр("ТаблицаШтрихкодов", ИсходнаяТаблицаШК);
ТаблицаДляЗаписи = Запрос.Выполнить().Выгрузить();
Для пропуска ресурсоемких типовых проверок и процедур очередей оборудования необходимо использовать свойство ОбменДанными.Загрузка = Истина. Обратите внимание, что это свойство доступно у объекта РегистрСведенийНаборЗаписей.
Важно: режим загрузки отключает прикладные проверки модулей конфигурации, поэтому корректность загружаемых данных (отсутствие пустых ссылок, валидность строк) должна быть гарантирована предварительным кодом.
Объединим запись отдельных строк в наборы записей с явным управлением транзакциями порциями по 500–1000 элементов. Это снижает количество фиксаций в журнале транзакций СУБД в сотни раз и обеспечивает высокую скорость выполнения.
Рассмотрим пример пакетной записи данных:
РазмерПорции = 1000;
ВсегоСтрок = ТаблицаДляЗаписи.Количество();
Индекс = 0;
Пока Индекс < ВсегоСтрок Цикл
НачатьТранзакцию();
Попытка
ГраницаПорции = Мин(Индекс + РазмерПорции, ВсегоСтрок);
Для ТекущийИндекс = Индекс По ГраницаПорции - 1 Цикл
СтрокаДанных = ТаблицаДляЗаписи[ТекущийИндекс];
НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Штрихкод.Установить(СтрокаДанных.Штрихкод);
// Отключаем выполнение типовых обработчиков событий
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Штрихкод = СтрокаДанных.Штрихкод;
НоваяЗапись.Номенклатура = СтрокаДанных.Номенклатура;
НоваяЗапись.Характеристика = СтрокаДанных.Характеристика;
НаборЗаписей.Записать(Истина);
КонецЦикла;
ЗафиксироватьТранзакцию();
Индекс = ГраницаПорции;
Исключение
ОтменитьТранзакцию();
ВызватьИсключение "Ошибка при записи порции штрихкодов: " + ОписаниеОшибки();
КонецПопытки;
КонецЦикла;
Применение наборов записей вместо РегистрСведенийМенеджерЗаписи, включение флага ОбменДанными.Загрузка = Истина, предварительная фильтрация дублей в запросе и объединение операций в порционные транзакции позволяют сократить время загрузки 10 000 штрихкодов с 40–60 минут до 5–15 секунд.