Часто при разработке на 1С мы сталкиваемся с ситуацией, когда казалось бы простой запрос начинает выполняться непозволительно долго. Давайте разберем классическую проблему производительности: запрос, содержащий условие В (&Параметр), где в качестве параметра передается список значений. В нашем примере запрос к регистру сведений с 11 элементами в списке выполнялся 7 секунд. Однако, стоило заменить условие на явное перечисление через ИЛИ (например, Поле = &П1 ИЛИ Поле = &П2...), как время выполнения сократилось до 1 секунды. Выясним причину такого поведения и проанализируем эффективные способы оптимизации.
Проблема кроется не в самой платформе 1С, а в механике работы оптимизатора базы данных (СУБД), например, MS SQL Server. Рассмотрим подробнее, что происходит "под капотом":
IN (@p1, @p2, ... @pN). Это заставляет сервер заново компилировать план, тратя ресурсы процессора.В то же время, когда мы жестко прописываем цепочку ИЛИ, оптимизатор более предсказуемо преобразует эти условия в операцию множественного поиска по индексу с последующим объединением результатов, что работает стабильно быстро.
Разберем решение, к которому пришел автор темы. Если список формируется динамически, мы можем программно сгенерировать текст запроса, заменив одно условие В на множество условий ИЛИ. Чтобы сделать это красиво и надежно, воспользуемся объектом СхемаЗапроса.
Этот подход отлично работает на небольших списках (10-15 элементов) и действительно снижает время выполнения до минимума. Однако он имеет минус: разбор AST-дерева через схему запроса создает небольшую дополнительную нагрузку на сервер приложений 1С.
Посмотрим на самый правильный и стабильный стандарт разработки для подобных задач — передачу Таблицы Значений (ТЗ) в качестве параметра запроса. Это устраняет любые проблемы с кэшем планов СУБД.
Вместо динамического формирования условий, мы помещаем наши элементы в типизированную таблицу на сервере и передаем ее в запрос. Рассмотрим пример кода:
// 1. Создаем типизированную ТЗ на стороне 1С
ТЗ_Процессы = Новый ТаблицаЗначений;
// Важно явно указать тип колонки, чтобы избежать ошибок СУБД
ТЗ_Процессы.Колонки.Добавить("БизнесПроцесс", Новый ОписаниеТипов("ДокументСсылка.Задание"));
Для Каждого Процесс Из СписокПроцессов Цикл
ТЗ_Процессы.Добавить().БизнесПроцесс = Процесс;
КонецЦикла;
// 2. Формируем один статический запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.БизнесПроцесс КАК БизнесПроцесс
|ПОМЕСТИТЬ ВТ_Процессы
|ИЗ
| &ТЗ_Процессы КАК ТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ДанныеБизнесПроцессов.ГлавнаяЗадача КАК ГлавнаяЗадача,
| ДанныеБизнесПроцессов.ВедущаяЗадача КАК ВедущаяЗадача,
| ДанныеБизнесПроцессов.БизнесПроцесс КАК Ссылка,
| ДанныеБизнесПроцессов.Наименование КАК Наименование,
| ДанныеБизнесПроцессов.Завершен КАК Выполнена,
| ДанныеБизнесПроцессов.Дата КАК Дата,
| ДанныеБизнесПроцессов.ПометкаУдаления КАК ПометкаУдаления
|ИЗ
| ВТ_Процессы КАК ВТ_Процессы
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеБизнесПроцессов КАК ДанныеБизнесПроцессов
| ПО ВТ_Процессы.БизнесПроцесс = ДанныеБизнесПроцессов.БизнесПроцесс
|УПОРЯДОЧИТЬ ПО
| Дата";
Запрос.УстановитьПараметр("ТЗ_Процессы", ТЗ_Процессы);
Результат = Запрос.Выполнить();
Преимущества этого метода:
Проанализируем структуру регистра. В 1С для регистров сведений кластерный индекс создается по измерениям в порядке их следования в конфигураторе. Если поле, по которому вы делаете отбор (в нашем случае БизнесПроцесс), является вторым или третьим измерением, поиск по условию ГДЕ БизнесПроцесс = ... не сможет эффективно использовать основной индекс (левая часть индекса отсутствует в отборе).
Чтобы ускорить такой запрос, необходимо в конфигураторе для нужного измерения установить свойство Индексировать. Платформа создаст дополнительный индекс в СУБД, где это поле будет первым, обеспечивая мгновенный поиск.
Часто разработчики передают в запрос СписокЗначений. С точки зрения СУБД разницы не будет, так как оба объекта разворачиваются в одинаковый SQL-код. Но для платформы 1С разница есть. СписокЗначений — это интерфейсный объект, который хранит представления, картинки и пометки. Его сериализация и передача между клиентом и сервером занимает больше памяти и времени. Возьмите за правило: в параметрах запросов следует использовать исключительно Массив или ТаблицуЗначений.
Интересно отметить, что в платформе 1С есть встроенный механизм оптимизации: если в массиве или списке более 128 элементов, платформа неявно (под капотом) сама создает временную таблицу и выполняет соединение. Проблемы с конструкцией В возникают именно на коротких списках (как у автора — 11 элементов), когда этот порог не достигнут, и запрос уходит в СУБД в виде IN. Принудительное использование Таблицы Значений избавляет нас от этих "сюрпризов" оптимизатора.