Гайд 1С: Оптимизация работы с табличными частями при пакетной обработке
- Обработка документов с десятками тысяч строк длится часами при 100% загрузке одного ядра процессора.
- Множественные циклические запросы к СУБД внутри конструкции
Для Каждого СтрокаТЧ Из...(ошибка «Запрос в цикле»). - Неконтролируемый рост времени выполнения транзакций и удержание блокировок.
1. Исключение запросов внутри цикла (Векторизация)
// НЕПРАВИЛЬНО: Запрос в цикле по строкам табличной части
Для Каждого Стр Из ДокументОбъект.Товары Цикл
Запрос = Новый Запрос("ВЫБРАТЬ Цена ИЗ РегистрСведений.ЦеныГдеНоменклатура = &Ном");
Запрос.УстановитьПараметр("Ном", Стр.Номенклатура);
Стр.Цена = Запрос.Выполнить().Выгрузить()[0].Цена;
КонецЦикла;
// ПРАВИЛЬНО: Пакетная передача всей ТЧ во временную таблицу
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ТЧ.НомерСтроки КАК НомерСтроки,
| ТЧ.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТабличнаяЧасть КАК ТЧ;
|////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.НомерСтроки,
| ЕСТЬNULL(Цены.Цена, 0) КАК Цена
|ИЗ
| ВТ_Товары КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены.СрезПоследних(&Период, ) КАК Цены
| ПО ВТ.Номенклатура = Цены.Номенклатура";
Запрос.УстановитьПараметр("ТабличнаяЧасть", ДокументОбъект.Товары.Выгрузить());
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Результат = Запрос.Выполнить();
ДокументОбъект.Товары.ЗагрузитьКолонку(Результат.Выгрузить().ВыгрузитьКолонку("Цена"), "Цена");2. Пакетная фиксация транзакций порциями
При обработке сотен тысяч строк разделяйте работу на кванты транзакций с явной фиксацией:
Счетчик = 0;
НачатьТранзакцию();
Для Каждого Строка Из МассивОбъектов Цикл
ОбработатьСтроку(Строка);
Счетчик = Счетчик + 1;
Если Счетчик % 1000 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию(); Частые вопросы (FAQ)
Почему запрос в цикле так сильно замедляет работу?
Каждый вызов запроса в цикле создает отдельный сетевой раундтрип между rphost и СУБД, компиляцию плана и наложение блокировок. Обработка 10 000 строк порождает 10 000 отдельных транзакций вместо одной пакетной.
Какой размер пачки (батча) транзакции считается оптимальным?
Оптимальный размер батча для 1С составляет от 500 до 2 000 объектов/строк. Меньший размер увеличивает накладные расходы на коммиты, больший — приводит к блокировкам и раздуванию журналов СУБД.
Как метод ЗагрузитьКолонку() сопоставляет строки?
Метод платформы 1С ЗагрузитьКолонку() выполняет прямое позиционное сопоставление по индексам элементов массива, работая на уровне низкоуровневой памяти C++ со скоростью в сотни раз выше перебора в цикле.
Создает ли передача ТЧ в запрос дополнительную нагрузку на tempdb?
Да, платформа создает физическую временную таблицу (#tt) в tempdb СУБД, но благодаря оптимизации Bulk Insert это происходит на порядки быстрее одиночных чтений.