Всем привет!
Есть определенный класс задач, в решении которых используется запрос в цикле. Я рассказываю о своем опыте, на истину в последней инстанции не претендую.
За 20 лет я сталкивался с задачами, в которых запрос в цикле это необходимая мера, и с ситуациями, в которых запрос в цикле это вынужденная мера, пусть и крадущая время выполнения кода.
В целом, я придерживаюсь мнения, что новичку нужно в процессе обучения, нарабатывания опыта и прогрессирования - исходить из той мысли, что использовать запрос в цикле "не комильфо".
Со временем программист научится различать ситуации и сценарии, когда нельзя использовать запрос в цикле, когда это критично, а когда это не критично.
Данная статья родилась в процессе обсуждений статьи Алгоритмы: улучшаем загрузку из эксель.
Класс задач, где запрещен запрос в цикле
Проведение документов
Например, в задаче получения себестоимости (остатка, последней цены и т.д.) товаров из документа. Идти по циклу по табличной части документа, в каждой итерации обращаться через запрос к регистрам для получения себестоимости (остатка, последней цены и т.д.) - это не правильно.
На курсе по программированию преподаватель мне сказал, что это неправильно, что это замедляет работу алгоритма. Как это проверить, тогда я не знал. Поэтому зарубил себе на носу, что за это снижают балл на экзамене.
Так всю жизнь и ходил в неведении, пока сам не разобрался что к чему.
Со временем я начал использовать замер производительности. Благодаря ему стал видеть и понимать, что использование запроса в цикле в определенных классах задач замедляет работу алгоритма.
А в процессах, где имеется конкурентная борьба за владение ресурсами, время выполнения транзакции становится критичным значением.
Так, к примеру, если расчет себестоимости (остатка, последней цены и т.д.) происходит в процедуре проведения документа, при этом документ делает записи в несколько регистров, и одномоментно с документами этого вида работают несколько пользователей, а с регистрами одномоментно работают несколько подразделений (закупки, продажи, склад) - то из-за длительного расчета алгоритма могут начаться блокировки регистров, в которые происходит запись движений документа.
Если же вы считаете себестоимость (остатки, последнюю цену и т.д.) не в процедуре проведения, а в своей внешней обработке для вывода в таблицу для дальнейшего анализа. И строк товаров в документе у вас немного, то смело можете прописывать запрос в цикле. Никто вам за это не снизит балл. Блокировок у вас не будет, иногда вы даже не заметите разницу во времени исполнения кода.
Вывод динамического списка
Если вы в динамическом списке будете отображать дополнительный показатель, то расчет этого показателя отдельно по каждой строке приведет к тому, что страница у пользователя будет открываться и обновляться долго, перемещение вниз по странице также будет тормозиться.
Для определения места в коде, которое выполняется больше всего времени, вам потребуется использовать режим отладки и замер производительности.
Разработчики платформы давно знали об этой особенности, и решили этот вопрос - предоставив нам, внедренцам и разработчикам приложений 1С, использовать метод ПриПолученииДанных().
Со временем я добавлю к статье алгоритмы для демонстрации.
А расширить класс задач, в которых запрос в цикле запрещено использовать, вы сможете самостоятельно. Исходя из примеров выше.
Класс задач, где запрос в цикле - необходимая мера.
Поиск номенклатуры с подходящими свойствами и характеристиками
Функция ПолучитьСписокХарактеристик()
ПустойМассив = Новый Массив;
Если ОтборПоСвойствам.Количество() = 0 Тогда
Возврат ПустойМассив;
КонецЕсли;
ТЗ = ОтборПоСвойствам.Скопировать(,);
ТЗ.Свернуть("Свойство");
СписокХарактеристик = Новый Массив;
Для Каждого СтрТЗ Из ТЗ Цикл
ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("Свойство", СтрТЗ.Свойство);
МассивСтрок = ОтборПоСвойствам.НайтиСтроки(ПараметрыПоиска);
СписокЗначенийСвойств = Новый Массив;
Для Каждого Стр Из МассивСтрок Цикл
//накапливаем список значений свойств
СписокЗначенийСвойств.Добавить(Стр.Значение);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Объект
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Свойство = &Свойство
| И ЗначенияСвойствОбъектов.Значение В(&СписокЗначенийСвойств)
| И ВЫБОР
| КОГДА &ИспользоватьСписокХарактеристик
| ТОГДА ЗначенияСвойствОбъектов.Объект В (&СписокХарактеристик)
| ИНАЧЕ ИСТИНА
| КОНЕЦ
| И ВЫБОР
| КОГДА &ИспользоватьСписокХарактеристик
| ТОГДА ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Объект КАК Справочник.ХарактеристикиНоменклатуры).ПометкаУдаления = ЛОЖЬ
| ИНАЧЕ ИСТИНА
| КОНЕЦ";
Запрос.УстановитьПараметр("Свойство", СтрТЗ.Свойство);
Запрос.УстановитьПараметр("СписокЗначенийСвойств", СписокЗначенийСвойств);
Запрос.УстановитьПараметр("ИспользоватьСписокХарактеристик", ?(СписокХарактеристик.Количество() = 0, Ложь, Истина));
Запрос.УстановитьПараметр("СписокХарактеристик", СписокХарактеристик);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат ПустойМассив;
КонецЕсли;
СписокХарактеристик = Результат.Выгрузить().ВыгрузитьКолонку("Объект");
КонецЦикла;
Возврат СписокХарактеристик;
КонецФункции
Вот этот алгоритм использован в работе Подбор номенклатуры по характеристикам - там суть такая - вы ставите одну галочку напротив свойства - определенный цвет/определенный размер и т.д., список номенклатуры уменьшается с каждым выбранным свойством.
Обратите внимание , в алгоритме используется запрос в цикле. Это другой класс задач.
Задача следующая. Выбираем номенклатуру по "Цвету": Красный или Белый или Зеленый, по "Материалу": либо пластик, либо пластик+. Сколько уже вариантов появилось? 6?
Нет, их 1000 - тысяча характеристик, потому что есть еще 20 других свойств с 100 разными значениями. И с каждым новым добавлением свойства и значений, список номенклатуры, которая подходит по характеристикам, сужается.
Поиск договоров с подходящими диапазонами наценок
Функция ПолучитьКоличествоДоговоров(Цепочка)
МассивСтрок = СтрРазделить(Цепочка,",",Ложь);
Если МассивСтрок.Количество()=0 Тогда
Возврат 0;
КонецЕсли;
СписокДоговоров = Новый Массив;
Для Каждого НомерСтроки Из МассивСтрок Цикл
Мин = ИсходнаяТаблица.Получить(НомерСтроки-1).Мин;
Макс = ИсходнаяТаблица.Получить(НомерСтроки-1).Макс;
Процент = ИсходнаяТаблица.Получить(НомерСтроки-1).Процент;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| НаценкиПоставщиков.ДоговорПоставки КАК ДоговорПоставки
|ИЗ
| РегистрСведений.НаценкиПоставщиков КАК НаценкиПоставщиков
|ГДЕ
| НаценкиПоставщиков.Мин = &Мин
| И НаценкиПоставщиков.Макс = &Макс
| И НаценкиПоставщиков.Процент = &Процент
| И НаценкиПоставщиков.Производитель = ЗНАЧЕНИЕ(Справочник.Производители.ПустаяСсылка)
| И НаценкиПоставщиков.ДоговорПоставки.ПометкаУдаления = ЛОЖЬ
| И (НаценкиПоставщиков.ДоговорПоставки.ДатаКонца = ДАТАВРЕМЯ(1, 1, 1)
| ИЛИ НаценкиПоставщиков.ДоговорПоставки.ДатаКонца > &ТекДата)
| И ВЫБОР
| КОГДА &ИспользоватьСписокДоговоров
| ТОГДА НаценкиПоставщиков.ДоговорПоставки В (&СписокДоговоров)
| ИНАЧЕ ИСТИНА
| КОНЕЦ";
Запрос.УстановитьПараметр("Мин" , Мин);
Запрос.УстановитьПараметр("Макс" , Макс);
Запрос.УстановитьПараметр("Процент" , Процент);
Запрос.УстановитьПараметр("ТекДата" , ТекущаяДата());
Запрос.УстановитьПараметр("ИспользоватьСписокДоговоров", ?(СписокДоговоров.Количество() = 0, Ложь, Истина));
Запрос.УстановитьПараметр("СписокДоговоров", СписокДоговоров);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат 0 ;
КонецЕсли;
СписокДоговоров = Результат.Выгрузить().ВыгрузитьКолонку("ДоговорПоставки");
КонецЦикла;
Возврат СписокДоговоров.Количество();
КонецФункции
С каждой итерацией круг поиска подходящих договоров сужается...
Класс задач, где запрос в цикле вынужденная мера
Связанные списки или структуры подчиненности
Для построения дерева нужно обратиться к СУБД для каждого родительского документа в поисках подчиненных - в целом работа с деревьями это всегда циклы и рекурсия.
Для построения связанных документов нужно использовать циклы, рекурсии и обращения к СУБД внутри цикла.
Групповые обработки документов
Запрос в цикле используется при групповом удалении документов - Удаление документов для любых баз на управляемых формах.
На этом все. Всем добра!
С пользой для клиентов, Рустем