Коллеги, здравствуйте!
Стал интересен момент падения производительности при работе с таблицей значения при обработке данных. Цель - выявить принцип, которого в дальнейшем следует придерживаться.
Чем руководствовался:
1. Обработка больших объемов данных занимает много времени;
2. Создание дополнительных объектов (речь про таблицу значений) - это накладные расходы, что влияет на производительность (в худшую сторону);
3. "Да, таблица значений - это зло, но это удобно и хочется понимать, сколько это стоит".
Начнем
Нам нужны данные и чтоб можно было утверждать, что их объем является достаточно большим (все очень условно). Я взял таблицу продаж.
Вот формирование запроса:
Функция ПолучитьЗапрос()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Продажи.Период,
| Продажи.Регистратор,
| Продажи.НомерСтроки,
| Продажи.Активность,
| Продажи.Номенклатура,
| Продажи.ХарактеристикаНоменклатуры,
| Продажи.ЗаказПокупателя,
| Продажи.ДоговорКонтрагента,
| Продажи.ДокументПродажи,
| Продажи.Подразделение,
| Продажи.Проект,
| Продажи.Организация,
| Продажи.Контрагент,
| Продажи.Акция,
| Продажи.Количество,
| Продажи.Стоимость,
| Продажи.СтоимостьБезСкидок,
| Продажи.НДС
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|ГДЕ
| Продажи.Период >= &ДатаНачала
| И Продажи.Период <= &ДатаОкончания";
Возврат Запрос;
КонецФункции
Условно выбираем период и делаем нарезки:
- сначала выбираем данные за первый день из периода;
- потом за 2 первых дня;
- потом за 3 первых дня;
- ...
- потом за весь период
Для каждого периода выполняем запрос, получаем объект РезультатЗапроса, дальше, работа идет уже именно с этим объектом.
ДатаОкончания = Период.ДатаОкончания;
ТекущаяДатаОкончания = КонецДня(Период.ДатаНачала);
Запрос = ПолучитьЗапрос();
Запрос.УстановитьПараметр("ДатаНачала", Период.ДатаНачала);
Пока ТекущаяДатаОкончания <= Период.ДатаОкончания Цикл
Запрос.УстановитьПараметр("ДатаОкончания", ТекущаяДатаОкончания);
РезультатЗапроса = Запрос.выполнить();
стр = Замеры.Добавить();
_Итоги_ДанныеВыборкой = ОбработатьДанныеВыборкой(РезультатЗапроса);
_Итоги_ДанныеТЗ = ОбработатьДанныеТЗ(РезультатЗапроса);
стр.КоличествоЗаписей = _Итоги_ДанныеВыборкой.КоличествоЗаписей;
стр.ВремяДляВыборки = _Итоги_ДанныеВыборкой.Время;
стр.ВремяДляТЗ = _Итоги_ДанныеТЗ.Время;
стр.Коэффициент = стр.ВремяДляТЗ/стр.ВремяДляВыборки;
ТекущаяДатаОкончания = КонецДня(ТекущаяДатаОкончания + 60*60*24);
КонецЦикла;
В данном контексте, время выполнения запроса нам не важно, нам важен этап дальнейшей обработки: через выборку или через таблицу значений.
Функция ОбработатьДанныеВыборкой(Результат)
КоличествоЗаписей = 0;
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
Выборка = Результат.Выбрать();
Пока выборка.следующий() Цикл
КоличествоЗаписей = КоличествоЗаписей + 1;
КонецЦикла;
Конец = ТекущаяУниверсальнаяДатаВМиллисекундах();
Возврат Новый структура("Время, КоличествоЗаписей", Конец-Начало, КоличествоЗаписей);
КонецФункции
Функция ОбработатьДанныеТЗ(Результат)
КоличествоЗаписей = 0;
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
тз = Результат.Выгрузить();
для каждого стр из тз Цикл
КоличествоЗаписей = КоличествоЗаписей + 1;
КонецЦикла;
Конец = ТекущаяУниверсальнаяДатаВМиллисекундах();
Возврат Новый структура("Время, КоличествоЗаписей", Конец-Начало, КоличествоЗаписей);
КонецФункции
Нам интересно, как дорого обойдется работа через таблицу значений по отношению к обычной выборке:
_Итоги_ДанныеВыборкой = ОбработатьДанныеВыборкой(РезультатЗапроса);
_Итоги_ДанныеТЗ = ОбработатьДанныеТЗ(РезультатЗапроса);
стр.КоличествоЗаписей = _Итоги_ДанныеВыборкой.КоличествоЗаписей;
стр.ВремяДляВыборки = _Итоги_ДанныеВыборкой.Время;
стр.ВремяДляТЗ = _Итоги_ДанныеТЗ.Время;
стр.Коэффициент = стр.ВремяДляТЗ/стр.ВремяДляВыборки;
Обработка написана для толстого клиента (думаю, для выведения принципа это не критично), результаты произвольных замеров приведены ниже:
Результат 1
Результат 2
Вывод
Таблица значений при обработке результатов запроса - это удобно, но это - зло. Коэффициент падения производительности будет лежать в диапазоне от 2,5 (это в оптимистичном случае) и более. Если не используются преимущества индексирования, то лучше избегать использования таблиц значений.
Тестировал на платформе 1С:Предприятие 8.3 (8.3.13.1644) в режиме совместимости с 8.2.13.
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 10.3, релизы 10.3.45.4