К статье
Практический материал

Разработка и Конфигурация · 10 мин

Чем заменить ИЛИ в запросе 1С: рабочие альтернативы

Чем заменить оператор ИЛИ в запросе 1С: оператор В, объединение таблиц, временные таблицы. Примеры кода, влияние на производительность и типичные ошибки.

Оператор ИЛИ в условиях запроса 1С — частый источник проблем с производительностью. Когда условий через ИЛИ много, а таблицы большие, СУБД может отказаться от использования индексов и начать полное сканирование таблицы. Запрос, который должен выполняться доли секунды, внезапно «виснет» на минуты, особенно после роста объёма данных.

Хорошая новость в том, что почти любую конструкцию с ИЛИ можно переписать другим способом: через оператор В, через объединение нескольких простых запросов, через временные таблицы или через пересмотр логики отбора. Выбор зависит от того, что именно вы проверяете: список значений одного поля, разные поля или сложные составные условия.

Ниже разобраны основные варианты замены с примерами кода, указаны случаи, когда ИЛИ допустимо и не вредит, и приведены способы проверить, действительно ли замена ускорила запрос.

Когда ИЛИ действительно становится проблемой

Сам по себе оператор ИЛИ не запрещён и не всегда медленный. Проблемы начинаются в типичных ситуациях: десятки условий через ИЛИ, сравнение разных полей, участие в условии неиндексированных полей, соединения таблиц с условием ИЛИ в секции связи. В этих случаях план запроса на стороне СУБД деградирует.

Особенно опасно ИЛИ в условиях соединения таблиц — такие связи почти всегда приводят к перебору. Также тяжёлым считается сочетание ИЛИ с функциями над полем (например, ПОДСТРОКА или подобие), потому что индекс по такому полю не используется.

Признак того, что пора переписывать запрос: время выполнения растёт быстрее, чем объём данных; запрос заметно медленнее на большой базе, чем на тестовой; в технологическом журнале видны длительные запросы именно с этим текстом.

2–3 условия ИЛИ по индексированным полямОбычно допустимо

Проверьте план запроса: если используется индекс, менять ничего не нужно

ИЛИ по разным полям таблицыРиск отказа от индексов

Рассмотрите разбиение на ОБЪЕДИНИТЬ

ИЛИ в условии соединенияПочти всегда медленно

Переписывайте на временные таблицы или В

Десятки значений одного поля через ИЛИЗаменяется оператором В

Передайте список параметром-массивом

Замена ИЛИ оператором В для списка значений

Самая частая ситуация — проверка одного поля на равенство нескольким значениям: ГДЕ Статус = &Статус1 ИЛИ Статус = &Статус2 ИЛИ Статус = &Статус3. Это напрямую заменяется оператором В: ГДЕ Статус В (&СписокСтатусов).

Параметр передаётся как массив или список значений из кода. Запрос становится короче, читаемее и быстрее: СУБД обрабатывает В по индексу эффективнее, чем цепочку ИЛИ, особенно при большом количестве значений.

Запрос.Текст =

"ВЫБРАТЬ

| Заказы.Ссылка

|ИЗ

| Документ.ЗаказКлиента КАК Заказы

|ГДЕ

| Заказы.Статус В (&Статусы)";

МассивСтатусов = Новый Массив;

МассивСтатусов.Добавить(Перечисления.СтатусыЗаказа.ВРаботе);

МассивСтатусов.Добавить(Перечисления.СтатусыЗаказа.КОтгрузке);

Запрос.УстановитьПараметр("Статусы", МассивСтатусов);

Дополнительный плюс: список значений можно формировать динамически, не перестраивая текст запроса. Это удобно, когда набор фильтров задаёт пользователь.

Разбиение на ОБЪЕДИНИТЬ вместо ИЛИ по разным полям

Когда условия через ИЛИ относятся к разным полям — например, ГДЕ Контрагент = &Контрагент ИЛИ Договор = &Договор — замена на В невозможна. Здесь рабочий приём: разбить запрос на несколько простых с ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ.

Каждая часть объединения использует свой индекс, и суммарно это часто быстрее одного запроса с ИЛИ. Используйте ОБЪЕДИНИТЬ, если пересечения между частями возможны и дубли недопустимы; ОБЪЕДИНИТЬ ВСЕ — быстрее, но вернёт дубли, если строка подходит под оба условия.

ВЫБРАТЬ

Расчёты.Ссылка КАК Документ

ИЗ

Документ.РеализацияТоваровУслуг КАК Расчёты

ГДЕ

Расчёты.Контрагент = &Контрагент

ОБЪЕДИНИТЬ

ВЫБРАТЬ

Расчёты.Ссылка

ИЗ

Документ.РеализацияТоваровУслуг КАК Расчёты

ГДЕ

Расчёты.Договор = &Договор

Ограничение приёма: если условий много, текст запроса раздувается, и поддерживать его становится труднее. При более чем трёх-четырёх ветках стоит подумать о временных таблицах или о пересмотре логики отбора.

Сравнение вариантов

Оператор В со списком

Подходит для одного поля и множества значений; не работает для условий по разным полям

ОБЪЕДИНИТЬ нескольких запросов

Подходит для условий по разным полям; текст запроса растёт, дубли зависят от вида объединения

Временные таблицы

Подходит для сложных многошаговых фильтров и больших пакетов; требует менеджера временных таблиц и аккуратной индексации

Оставить ИЛИ

Допустимо при 2–3 условиях по индексированным полям; риск деградации при росте данных

Временные таблицы для сложных фильтров

Если условие с ИЛИ строится по результатам другого запроса или по сложной логике, эффективнее вынести отбор во временную таблицу, а затем соединиться с ней. Это стандартный приём оптимизации в 1С: сначала помещаете нужные ссылки во временную таблицу, индексируете её, потом используете в основном запросе.

ВЫБРАТЬ

Заказы.Ссылка КАК Ссылка

ПОМЕСТИТЬ ВТ_Отобранные

ИЗ

Документ.ЗаказКлиента КАК Заказы

ГДЕ

Заказы.Статус В (&Статусы)

ИНДЕКСИРОВАТЬ ПО

Ссылка

;

ВЫБРАТЬ

Товары.Ссылка,

Товары.Номенклатура

ИЗ

Документ.ЗаказКлиента.Товары КАК Товары

ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Отобранные КАК Отбор

ПО Товары.Ссылка = Отбор.Ссылка

Такой подход заменяет не только ИЛИ, но и виртуальные обращения вроде «получить документы, у которых в табличной части есть хотя бы одна строка с условием А или Б». Сначала собираете ссылки документов во временную таблицу одним компактным запросом, затем работаете уже с ней.

Не забывайте про индексацию временной таблицы по полям соединения — без индекса выигрыш может обернуться потерей. И уничтожайте временные таблицы, когда они больше не нужны, если пакет запросов длинный.

Порядок действий при оптимизации запроса с ИЛИ
  1. 1
    Определите, что проверяет ИЛИ: одно поле со многими значениями или разные поля
  2. 2
    Для одного поля замените цепочку на оператор В с параметром-массивом
  3. 3
    Для разных полей разбейте запрос на части через ОБЪЕДИНИТЬ
  4. 4
    При сложной логике вынесите отбор во временную таблицу с индексом
  5. 5
    Сравните время выполнения до и после на копии рабочей базы
  6. 6
    Проверьте, что результат запроса не изменился: состав строк и их количество

ИЛИ в условиях соединения: как переписать

Соединение таблиц с ИЛИ в условии связи — самый тяжёлый случай. Конструкция вида ПО Т1.Поле = Т2.Поле1 ИЛИ Т1.Поле = Т2.Поле2 заставляет СУБД перебирать комбинации строк. Прямой замены в синтаксисе 1С нет, поэтому запрос перестраивают.

Рабочие варианты: два отдельных соединения с последующим объединением результатов; предварительная нормализация данных во временной таблице (привести оба поля к одному виду); пересмотр схемы данных, если такая связь нужна постоянно — возможно, стоит хранить единый ключ.

Если соединение с ИЛИ встречается в типовом запросе динамического списка или отчёта СКД, сначала проверьте, нельзя ли добиться того же результата настройкой отборов: отборы СКД по списку значений внутри преобразуются в оператор В, что эффективнее.

Проверка результата и типичные ошибки

После замены сравните старый и новый запросы: количество строк, итоговые суммы, состав ссылок. Удобно выполнить оба запроса на одних данных и сверить выгрузки в таблицы значений. Расхождение почти всегда означает, что при разбиении потерялась часть условий или появились дубли.

Для оценки скорости используйте замер времени выполнения на базе, приближенной к рабочей по объёму. На маленькой тестовой базе разница между ИЛИ и В может быть незаметна, а на большой — кратной.

Типичные ошибки
01
Замена ИЛИ на ОБЪЕДИНИТЬ ВСЕ без проверки пересечений — появляются дубли строк и завышенные итоги
02
Передача в оператор В пустого массива без дополнительной логики — запрос молча возвращает пустой результат
03
Забытая индексация временной таблицы — соединение с ней работает медленнее исходного ИЛИ
04
Проверка оптимизации только на тестовой базе с малым объёмом — на рабочей базе эффект не подтверждается
05
Смешение ИЛИ и И без скобок — меняется логика условия и результат становится непредсказуемым

Отдельно отметьте приоритет операторов: И выполняется раньше ИЛИ. Условие А И Б ИЛИ В читается как (А И Б) ИЛИ В. При переписывании всегда расставляйте скобки явно — это защищает от ошибок и облегчает чтение.

Итог

Что важно запомнить

Списки значений одного поля заменяйте оператором В с параметром-массивом. Условия по разным полям разбивайте через ОБЪЕДИНИТЬ. Сложную логику выносите во временные таблицы с индексацией. ИЛИ в соединениях переписывайте всегда. Любую замену проверяйте по составу результата и времени выполнения на копии базы.

Частые вопросы

Оператор В всегда быстрее, чем ИЛИ?

Нет, при двух-трёх значениях и индексированном поле разница может быть незаметна. Выигрыш В проявляется при большом количестве значений и крупных таблицах, а также в читаемости и удобстве динамического формирования списка.

Можно ли передать в оператор В таблицу значений?

Да, параметром можно передать таблицу значений, но тогда в запросе её нужно сначала поместить во временную таблицу конструкцией В (&ТЗ) и далее соединяться с ней. Для простого списка значений достаточно массива.

Чем ОБЪЕДИНИТЬ отличается от ОБЪЕДИНИТЬ ВСЕ?

ОБЪЕДИНИТЬ исключает дубли строк и работает медленнее из-за дополнительной обработки. ОБЪЕДИНИТЬ ВСЕ возвращает все строки из всех частей, включая дубли. Если части заведомо не пересекаются, используйте ОБЪЕДИНИТЬ ВСЕ — это быстрее.

Как увидеть, использует ли запрос индексы?

В 1С нет встроенного просмотра плана запроса, поэтому используют средства СУБД: для MS SQL — план выполнения в Management Studio, для PostgreSQL — команду EXPLAIN. Косвенно о проблемах говорит анализ длительных запросов в технологическом журнале.

Что делать, если ИЛИ формируется динамически в тексте запроса?

Замените конкатенацию условий на параметр-список с оператором В там, где проверяется одно поле. Если условия разнородные, формируйте текст запроса из отдельных блоков с ОБЪЕДИНИТЬ — так проще контролировать параметры и избежать ошибок синтаксиса.

Влияет ли ИЛИ на запросы в СКД так же, как на обычные?

Да, механика та же: СКД в итоге формирует запрос к СУБД, и тяжёлые условия в тексте набора данных тормозят отчёт. Предпочтительнее выносить фильтры в настройки отбора СКД — там список значений обрабатывается через В.