Как ускорить массовую запись штрихкодов в регистр сведений в 1С

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

При пакетной загрузке данных, например при импорте нескольких тысяч или десятков тысяч штрихкодов номенклатуры в конфигурации «1С:Розница» или «1С:Управление торговлей», разработчики часто сталкиваются с крайне низкой производительностью. Запись относительно небольшого объема данных (10 000 строк) стандартным перебором через объект РегистрСведенийМенеджерЗаписи может занимать до часа и более. Рассмотрим подробно, почему возникает эта проблема, какие ограничения платформы 1С необходимо учитывать и как правильно оптимизировать процесс массовой записи.

Выясним причины низкой скорости записи

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

  1. Избыточное количество транзакций СУБД. При использовании МенеджерЗаписи.Записать() платформа открывает и фиксирует отдельную транзакцию на уровне СУБД для каждой отдельной строки. Для 10 000 записей это означает 10 000 физических обращений к журналу транзакций дисковой подсистемы, что создает критическую нагрузку на ввод-вывод.
  2. Выполнение типовых проверок и подписок на события. В типовых конфигурациях в модуле набора записей регистра и подписках на события при каждой записи выполняются многочисленные алгоритмы: проверка уникальности штрихкода, валидация формата, постановка заданий на очередь выгрузки в подключаемое оборудование (весы, ККМ Offline), расчет хэшей и др.
  3. Автоматическая регистрация изменений для планов обмена. Если регистр входит в состав планов обмена (например, РИБ по магазинам), для каждой записи платформа выполняет дополнительные операции вставки в таблицы изменений, многократно увеличивая накладные расходы.

Ограничения платформы: работа с отборами и транзакциями

Разберем важные платформенные особенности, которые влияют на выбор алгоритма оптимизации:

  1. Отбор по списку значений не поддерживается. В объекте РегистрСведенийНаборЗаписей свойство Отбор поддерживает исключительно вид сравнения Равно. Передать массив или список значений номенклатуры в отбор набора записей платформенно невозможно.
  2. Особенности перехвата исключений внутри транзакций. В клиент-серверном варианте платформы 1С, если внутри открытой транзакции возникает ошибка (даже если она обработана конструкцией Попытка ... Исключение), транзакция на уровне СУБД автоматически помечается как недействительная. Вызов метода ЗафиксироватьТранзакцию() после этого приведет к аварийному падению с ошибкой «Транзакция уже отменена». Поэтому вся транзакция целиком должна обрамляться блоком попытки.

Шаг 1. Предварительная очистка и проверка дублей запросом

Перед записью данных в регистр необходимо отсечь внутренние дубликаты штрихкодов в исходной таблице и проверить их наличие в базе, чтобы избежать системных исключений нарушения уникальности записей СУБД. Посмотрим на пример проверки через временную таблицу:


Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = 
"ВЫБРАТЬ
|	ТШК.Штрихкод КАК Штрихкод,
|	ТШК.Номенклатура КАК Номенклатура,
|	ТШК.Характеристика КАК Характеристика
|ПОМЕСТИТЬ ВТ_ИсходныеШК
|ИЗ
|	&ТаблицаШтрихкодов КАК ТШК
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
|	ВТ.Штрихкод КАК Штрихкод,
|	ВТ.Номенклатура КАК Номенклатура,
|	ВТ.Характеристика КАК Характеристика
|ИЗ
|	ВТ_ИсходныеШК КАК ВТ
|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК РСШК
|		ПО ВТ.Штрихкод = РСШК.Штрихкод
|ГДЕ
|	РСШК.Штрихкод ЕСТЬ NULL";

Запрос.УстановитьПараметр("ТаблицаШтрихкодов", ИсходнаяТаблицаШК);
ТаблицаДляЗаписи = Запрос.Выполнить().Выгрузить();

Шаг 2. Отключение типовой бизнес-логики через режим загрузки

Для пропуска ресурсоемких типовых проверок и процедур очередей оборудования необходимо использовать свойство ОбменДанными.Загрузка = Истина. Обратите внимание, что это свойство доступно у объекта РегистрСведенийНаборЗаписей.

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

Шаг 3. Пакетная запись порциями в транзакциях

Объединим запись отдельных строк в наборы записей с явным управлением транзакциями порциями по 500–1000 элементов. Это снижает количество фиксаций в журнале транзакций СУБД в сотни раз и обеспечивает высокую скорость выполнения.

Рассмотрим пример пакетной записи данных:


РазмерПорции = 1000;
ВсегоСтрок = ТаблицаДляЗаписи.Количество();
Индекс = 0;

Пока Индекс < ВсегоСтрок Цикл
	
	НачатьТранзакцию();
	Попытка
		ГраницаПорции = Мин(Индекс + РазмерПорции, ВсегоСтрок);
		
		Для ТекущийИндекс = Индекс По ГраницаПорции - 1 Цикл
			СтрокаДанных = ТаблицаДляЗаписи[ТекущийИндекс];
			
			НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();
			НаборЗаписей.Отбор.Штрихкод.Установить(СтрокаДанных.Штрихкод);
			
			// Отключаем выполнение типовых обработчиков событий
			НаборЗаписей.ОбменДанными.Загрузка = Истина;
			
			НоваяЗапись = НаборЗаписей.Добавить();
			НоваяЗапись.Штрихкод = СтрокаДанных.Штрихкод;
			НоваяЗапись.Номенклатура = СтрокаДанных.Номенклатура;
			НоваяЗапись.Характеристика = СтрокаДанных.Характеристика;
			
			НаборЗаписей.Записать(Истина);
		КонецЦикла;
		
		ЗафиксироватьТранзакцию();
		Индекс = ГраницаПорции;
		
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение "Ошибка при записи порции штрихкодов: " + ОписаниеОшибки();
	КонецПопытки;
	
КонецЦикла;

Итоги оптимизации

Применение наборов записей вместо РегистрСведенийМенеджерЗаписи, включение флага ОбменДанными.Загрузка = Истина, предварительная фильтрация дублей в запросе и объединение операций в порционные транзакции позволяют сократить время загрузки 10 000 штрихкодов с 40–60 минут до 5–15 секунд.

← На главную