Зачем пакетировать
- Ограничения СУБД/движка по размеру запроса и числу параметров.
- Стабильная производительность: много маленьких запросов лучше, чем один гигантский.
- Контроль памяти: не держим «всё сразу» в ТаблицаЗначений.
Два паттерна: батчинг списков (IN) и параметры-таблицы (&ВТ).
Паттерн 1 — батчинг списков (IN &Список)
Делим большой массив ссылок на чанки по 200–1000 элементов и вытягиваем данные порциями.
Утилита: разбиение массива на чанки
Функция РазбитьНаЧанки(ИсхМассив, РазмерЧанка) Экспорт
Рез = Новый Массив;
Если РазмерЧанка <= 0 Тогда Возврат Рез; КонецЕсли;
Тек = Новый Массив;
Для каждого Э Из ИсхМассив Цикл
Тек.Добавить(Э);
Если Тек.Количество() >= РазмерЧанка Тогда
Рез.Добавить(Тек);
Тек = Новый Массив;
КонецЕсли;
КонецЦикла;
Если Тек.Количество() > 0 Тогда Рез.Добавить(Тек); КонецЕсли;
Возврат Рез;
КонецФункции
Выгрузка по ID батчами
Функция НомПоIDБатчами(IDsМассив, РазмерЧанка = 500) Экспорт
ТекстQ = "
|ВЫБРАТЬ
| Ном.Ссылка КАК ID,
| Ном.Наименование КАК Name
|ИЗ Справочник.Номенклатура КАК Ном
|ГДЕ Ном.Ссылка В (&Список)
";
Результ = Новый ТаблицаЗначений;
Результ.Колонки.Добавить("ID");
Результ.Колонки.Добавить("Name");
Для каждого Чанк Из РазбитьНаЧанки(IDsМассив, РазмерЧанка) Цикл
Таб = A1sQ.Unload(ТекстQ, Чанк); // порядок: &Список
Результ.ЗагрузитьКолонку(Таб.ВыгрузитьКолонку("ID"), "ID");
Результ.ЗагрузитьКолонку(Таб.ВыгрузитьКолонку("Name"), "Name");
A1sLog.Info("Day9", "Загружен чанк: " + Чанк.Количество() + " id");
КонецЦикла;
Возврат Результ;
КонецФункции
Подходит для средних наборов. Для очень больших — смотрите параметры-таблицы.
Паттерн 2 — параметр-таблица (&ВТ) + JOIN
Создаём ТаблицаЗначений с колонкой ID, передаём как параметр
&IDs и соединяем её в запросе как виртуальную таблицу.
Подготовка параметра-таблицы
Функция СформироватьВТ_ID(IDsМассив) Экспорт
ВТ = Новый ТаблицаЗначений;
ВТ.Колонки.Добавить("ID"); // тип ссылки на справочник Номенклатура
Для каждого Id Из IDsМассив Цикл
НовСтр = ВТ.Добавить();
НовСтр.ID = Id;
КонецЦикла;
Возврат ВТ;
КонецФункции
Выборка по &IDs через JOIN (эффективно для больших наборов)
Функция НомПоIDsЧерезВТ(IDsМассив) Экспорт
ВТ = СформироватьВТ_ID(IDsМассив);
ТекстQ = "
|ВЫБРАТЬ
| Ном.Ссылка КАК ID,
| Ном.Наименование КАК Name
|ИЗ Справочник.Номенклатура КАК Ном
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ &IDs КАК ВТ
| ПО Ном.Ссылка = ВТ.ID
|УПОРЯДОЧИТЬ ПО Name
";
// Параметры позиционно: &IDs
Возврат A1sQ.Unload(ТекстQ, ВТ);
КонецФункции
Этот подход разгружает парсер от длинных «IN (...)» и хорошо работает на больших списках.
Пакетная обработка по периодам
Гоняем запрос «окнами» по дате: день/неделя/месяц. Логируем прогресс.
Процедура ОбработатьРеализацииПоМесяцам(НачПериода, КонПериода) Экспорт
МесяцНач = НачалоМесяца(НачПериода);
Пока МесяцНач <= КонПериода Цикл
МесяцКон = КонецМесяца(МесяцНач);
ТекстQ = "
|ВЫБРАТЬ
| Док.Ссылка КАК ID,
| Док.Дата КАК Dt,
| Док.СуммаДокумента КАК Amount
|ИЗ Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ Док.Дата МЕЖДУ &Начало И &Конец
";
Рез = A1sQ.ExecuteQ(ТекстQ, МесяцНач, МесяцКон);
Вб = Рез.Выбрать();
Сумма = 0; Сч = 0;
Пока Вб.Следующий() Цикл
Сумма = Сумма + Вб.Amount;
Сч = Сч + 1;
КонецЦикла;
A1sLog.Info("Day9", Формат(МесяцНач, "ДФ=MM.YYYY") + ": док=" + Сч + ", сумма=" + Сумма);
МесяцНач = НачалоМесяца(МесяцНач + 31*СекундаВСутках);
КонецЦикла;
КонецПроцедуры
Если выборка за месяц всё равно тяжёлая — добавляйте ПЕРВЫЕ &Лимит и
keyset-пагинацию (см. День 7).
Объединение результатов батчей
Иногда нужно одно соответствие ID → Name из многих батчей.
Функция КартаIDкИмени_Батчи(IDs, РазмерЧанка = 500) Экспорт
ТекстQ = "
|ВЫБРАТЬ
| Ном.Ссылка КАК ID,
| Ном.Наименование КАК Name
|ИЗ Справочник.Номенклатура КАК Ном
|ГДЕ Ном.Ссылка В (&Список)
";
Карта = Новый Соответствие;
Для каждого Ч Из РазбитьНаЧанки(IDs, РазмерЧанка) Цикл
Таб = A1sQ.Unload(ТекстQ, Ч);
IDsЧ = Таб.ВыгрузитьКолонку("ID");
NamesЧ = Таб.ВыгрузитьКолонку("Name");
Для Н = 0 По IDsЧ.Количество()-1 Цикл
Карта.Вставить(IDsЧ[Н], NamesЧ[Н]);
КонецЦикла;
A1sLog.Info("Day9", "Карта: +" + Таб.Количество() + " пар");
КонецЦикла;
Возврат Карта;
КонецФункции
Контроль ошибок и таймаутов
- Ставьте разумный размер чанка (200–1000) и измеряйте время (см. День 7: UnloadTimed).
- В батч-цикле используйте
Попытка/Исключение, логируйте и продолжайте со следующего чанка. - Кэшируйте уже обработанные ID (напр., Соответствие), чтобы повторный запуск не делал лишнюю работу.
Процедура ОбработатьБатчиСЗащитой(IDs) Экспорт
Для каждого Ч Из РазбитьНаЧанки(IDs, 500) Цикл
Попытка
Таб = A1sQ.Unload("
|ВЫБРАТЬ Ном.Ссылка КАК ID, Ном.Наименование КАК Name
|ИЗ Справочник.Номенклатура КАК Ном
|ГДЕ Ном.Ссылка В (&Список)
", Ч);
A1sLog.Info("Day9", "OK чанк: " + Ч.Количество() + " id");
Исключение
A1sLog.Error("Day9", "FAIL чанк: " + ОписаниеОшибки());
Продолжить; // следующий чанк
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Практика (15–30 минут)
- Соберите батч-выборку по списку ссылок через
В (&Список)(чанк 500). - Сделайте вариант с параметром-таблицей
&IDsиJOIN— сравните время. - Реализуйте обработку документов по месяцам и залогируйте сумму/кол-во по каждому месяцу.
- Соберите «карту»
ID → Nameиз батчей и проверьте уникальность ключей.
Чек-лист
- □ Выбран способ пакетирования: IN-батчи или параметр-таблица.
- □ Размер чанка подобран по замерам, логируется прогресс.
- □ Не тянем лишние поля, сортировки — только когда нужны.
- □ Есть защита
Попытка/Исключениеи продолжение после ошибки.
Что дальше
День 10: A1sO — проверки значений (Empty, NotEmpty) и базовые предикаты.