Разработка и Конфигурация · 10 мин
Чем заменить ИЛИ в запросе 1С: рабочие альтернативы
Чем заменить оператор ИЛИ в запросе 1С: оператор В, объединение таблиц, временные таблицы. Примеры кода, влияние на производительность и типичные ошибки.
Оператор ИЛИ в условиях запроса 1С — частый источник проблем с производительностью. Когда условий через ИЛИ много, а таблицы большие, СУБД может отказаться от использования индексов и начать полное сканирование таблицы. Запрос, который должен выполняться доли секунды, внезапно «виснет» на минуты, особенно после роста объёма данных.
Хорошая новость в том, что почти любую конструкцию с ИЛИ можно переписать другим способом: через оператор В, через объединение нескольких простых запросов, через временные таблицы или через пересмотр логики отбора. Выбор зависит от того, что именно вы проверяете: список значений одного поля, разные поля или сложные составные условия.
Ниже разобраны основные варианты замены с примерами кода, указаны случаи, когда ИЛИ допустимо и не вредит, и приведены способы проверить, действительно ли замена ускорила запрос.
Когда ИЛИ действительно становится проблемой
Сам по себе оператор ИЛИ не запрещён и не всегда медленный. Проблемы начинаются в типичных ситуациях: десятки условий через ИЛИ, сравнение разных полей, участие в условии неиндексированных полей, соединения таблиц с условием ИЛИ в секции связи. В этих случаях план запроса на стороне СУБД деградирует.
Особенно опасно ИЛИ в условиях соединения таблиц — такие связи почти всегда приводят к перебору. Также тяжёлым считается сочетание ИЛИ с функциями над полем (например, ПОДСТРОКА или подобие), потому что индекс по такому полю не используется.
Признак того, что пора переписывать запрос: время выполнения растёт быстрее, чем объём данных; запрос заметно медленнее на большой базе, чем на тестовой; в технологическом журнале видны длительные запросы именно с этим текстом.
Проверьте план запроса: если используется индекс, менять ничего не нужно
Рассмотрите разбиение на ОБЪЕДИНИТЬ
Переписывайте на временные таблицы или В
Передайте список параметром-массивом
Замена ИЛИ оператором В для списка значений
Самая частая ситуация — проверка одного поля на равенство нескольким значениям: ГДЕ Статус = &Статус1 ИЛИ Статус = &Статус2 ИЛИ Статус = &Статус3. Это напрямую заменяется оператором В: ГДЕ Статус В (&СписокСтатусов).
Параметр передаётся как массив или список значений из кода. Запрос становится короче, читаемее и быстрее: СУБД обрабатывает В по индексу эффективнее, чем цепочку ИЛИ, особенно при большом количестве значений.
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Ссылка
|ИЗ
| Документ.ЗаказКлиента КАК Заказы
|ГДЕ
| Заказы.Статус В (&Статусы)";
МассивСтатусов = Новый Массив;
МассивСтатусов.Добавить(Перечисления.СтатусыЗаказа.ВРаботе);
МассивСтатусов.Добавить(Перечисления.СтатусыЗаказа.КОтгрузке);
Запрос.УстановитьПараметр("Статусы", МассивСтатусов);
Дополнительный плюс: список значений можно формировать динамически, не перестраивая текст запроса. Это удобно, когда набор фильтров задаёт пользователь.
Разбиение на ОБЪЕДИНИТЬ вместо ИЛИ по разным полям
Когда условия через ИЛИ относятся к разным полям — например, ГДЕ Контрагент = &Контрагент ИЛИ Договор = &Договор — замена на В невозможна. Здесь рабочий приём: разбить запрос на несколько простых с ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ.
Каждая часть объединения использует свой индекс, и суммарно это часто быстрее одного запроса с ИЛИ. Используйте ОБЪЕДИНИТЬ, если пересечения между частями возможны и дубли недопустимы; ОБЪЕДИНИТЬ ВСЕ — быстрее, но вернёт дубли, если строка подходит под оба условия.
ВЫБРАТЬ
Расчёты.Ссылка КАК Документ
ИЗ
Документ.РеализацияТоваровУслуг КАК Расчёты
ГДЕ
Расчёты.Контрагент = &Контрагент
ОБЪЕДИНИТЬ
ВЫБРАТЬ
Расчёты.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК Расчёты
ГДЕ
Расчёты.Договор = &Договор
Ограничение приёма: если условий много, текст запроса раздувается, и поддерживать его становится труднее. При более чем трёх-четырёх ветках стоит подумать о временных таблицах или о пересмотре логики отбора.
Сравнение вариантов
Подходит для одного поля и множества значений; не работает для условий по разным полям
Подходит для условий по разным полям; текст запроса растёт, дубли зависят от вида объединения
Подходит для сложных многошаговых фильтров и больших пакетов; требует менеджера временных таблиц и аккуратной индексации
Допустимо при 2–3 условиях по индексированным полям; риск деградации при росте данных
Временные таблицы для сложных фильтров
Если условие с ИЛИ строится по результатам другого запроса или по сложной логике, эффективнее вынести отбор во временную таблицу, а затем соединиться с ней. Это стандартный приём оптимизации в 1С: сначала помещаете нужные ссылки во временную таблицу, индексируете её, потом используете в основном запросе.
ВЫБРАТЬ
Заказы.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Отобранные
ИЗ
Документ.ЗаказКлиента КАК Заказы
ГДЕ
Заказы.Статус В (&Статусы)
ИНДЕКСИРОВАТЬ ПО
Ссылка
;
ВЫБРАТЬ
Товары.Ссылка,
Товары.Номенклатура
ИЗ
Документ.ЗаказКлиента.Товары КАК Товары
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Отобранные КАК Отбор
ПО Товары.Ссылка = Отбор.Ссылка
Такой подход заменяет не только ИЛИ, но и виртуальные обращения вроде «получить документы, у которых в табличной части есть хотя бы одна строка с условием А или Б». Сначала собираете ссылки документов во временную таблицу одним компактным запросом, затем работаете уже с ней.
Не забывайте про индексацию временной таблицы по полям соединения — без индекса выигрыш может обернуться потерей. И уничтожайте временные таблицы, когда они больше не нужны, если пакет запросов длинный.
- 1Определите, что проверяет ИЛИ: одно поле со многими значениями или разные поля
- 2Для одного поля замените цепочку на оператор В с параметром-массивом
- 3Для разных полей разбейте запрос на части через ОБЪЕДИНИТЬ
- 4При сложной логике вынесите отбор во временную таблицу с индексом
- 5Сравните время выполнения до и после на копии рабочей базы
- 6Проверьте, что результат запроса не изменился: состав строк и их количество
ИЛИ в условиях соединения: как переписать
Соединение таблиц с ИЛИ в условии связи — самый тяжёлый случай. Конструкция вида ПО Т1.Поле = Т2.Поле1 ИЛИ Т1.Поле = Т2.Поле2 заставляет СУБД перебирать комбинации строк. Прямой замены в синтаксисе 1С нет, поэтому запрос перестраивают.
Рабочие варианты: два отдельных соединения с последующим объединением результатов; предварительная нормализация данных во временной таблице (привести оба поля к одному виду); пересмотр схемы данных, если такая связь нужна постоянно — возможно, стоит хранить единый ключ.
Если соединение с ИЛИ встречается в типовом запросе динамического списка или отчёта СКД, сначала проверьте, нельзя ли добиться того же результата настройкой отборов: отборы СКД по списку значений внутри преобразуются в оператор В, что эффективнее.
Проверка результата и типичные ошибки
После замены сравните старый и новый запросы: количество строк, итоговые суммы, состав ссылок. Удобно выполнить оба запроса на одних данных и сверить выгрузки в таблицы значений. Расхождение почти всегда означает, что при разбиении потерялась часть условий или появились дубли.
Для оценки скорости используйте замер времени выполнения на базе, приближенной к рабочей по объёму. На маленькой тестовой базе разница между ИЛИ и В может быть незаметна, а на большой — кратной.
Отдельно отметьте приоритет операторов: И выполняется раньше ИЛИ. Условие А И Б ИЛИ В читается как (А И Б) ИЛИ В. При переписывании всегда расставляйте скобки явно — это защищает от ошибок и облегчает чтение.
Что важно запомнить
Списки значений одного поля заменяйте оператором В с параметром-массивом. Условия по разным полям разбивайте через ОБЪЕДИНИТЬ. Сложную логику выносите во временные таблицы с индексацией. ИЛИ в соединениях переписывайте всегда. Любую замену проверяйте по составу результата и времени выполнения на копии базы.
Частые вопросы
Оператор В всегда быстрее, чем ИЛИ?
Нет, при двух-трёх значениях и индексированном поле разница может быть незаметна. Выигрыш В проявляется при большом количестве значений и крупных таблицах, а также в читаемости и удобстве динамического формирования списка.
Можно ли передать в оператор В таблицу значений?
Да, параметром можно передать таблицу значений, но тогда в запросе её нужно сначала поместить во временную таблицу конструкцией В (&ТЗ) и далее соединяться с ней. Для простого списка значений достаточно массива.
Чем ОБЪЕДИНИТЬ отличается от ОБЪЕДИНИТЬ ВСЕ?
ОБЪЕДИНИТЬ исключает дубли строк и работает медленнее из-за дополнительной обработки. ОБЪЕДИНИТЬ ВСЕ возвращает все строки из всех частей, включая дубли. Если части заведомо не пересекаются, используйте ОБЪЕДИНИТЬ ВСЕ — это быстрее.
Как увидеть, использует ли запрос индексы?
В 1С нет встроенного просмотра плана запроса, поэтому используют средства СУБД: для MS SQL — план выполнения в Management Studio, для PostgreSQL — команду EXPLAIN. Косвенно о проблемах говорит анализ длительных запросов в технологическом журнале.
Что делать, если ИЛИ формируется динамически в тексте запроса?
Замените конкатенацию условий на параметр-список с оператором В там, где проверяется одно поле. Если условия разнородные, формируйте текст запроса из отдельных блоков с ОБЪЕДИНИТЬ — так проще контролировать параметры и избежать ошибок синтаксиса.
Влияет ли ИЛИ на запросы в СКД так же, как на обычные?
Да, механика та же: СКД в итоге формирует запрос к СУБД, и тяжёлые условия в тексте набора данных тормозят отчёт. Предпочтительнее выносить фильтры в настройки отбора СКД — там список значений обрабатывается через В.