При написании запросов в системе 1С:Предприятие программисты часто сталкиваются с необходимостью отфильтровать данные по нескольким значениям одного перечисления. Например, нужно выбрать документы «Чек ККМ», которые находятся в статусе «Пробитый» или «Архивный». Несмотря на кажущуюся простоту, здесь есть свои синтаксические нюансы и правила оптимизации, которые важно соблюдать для обеспечения высокой скорости работы системы.
В этой статье мы подробно разберем, как правильно составить такие условия, рассмотрим различные подходы и выясним, какой из них является наиболее эффективным с точки зрения производительности СУБД.
Это самый распространенный и рекомендуемый способ, если перечень значений заранее известен и фиксирован прямо в тексте запроса. Для этого используется конструкция ЗНАЧЕНИЕ(), а сами значения перечисляются через запятую внутри круглых скобок после оператора В.
Разберем конкретный пример синтаксиса:
ВЫБРАТЬ
ЧекККМ.Ссылка КАК Ссылка,
ЧекККМ.Номер КАК Номер
ИЗ
Документ.ЧекККМ КАК ЧекККМ
ГДЕ
ЧекККМ.СтатусЧекаККМ В (ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Архивный),
ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Пробитый))
Важный нюанс: Обратите внимание, что мы не используем логическое «ИЛИ» внутри конструкции ЗНАЧЕНИЕ(). Платформа ожидает именно перечисление объектов метаданных через запятую. Если написать В (ЗНАЧЕНИЕ(...) ИЛИ ЗНАЧЕНИЕ(...)), система выдаст синтаксическую ошибку, так как внутри скобок оператора В должен быть список, а не логическое выражение.
Если по каким-то причинам использование оператора В кажется неудобным, можно прибегнуть к классическому сравнению через ИЛИ. В этом случае каждое условие должно быть полным (поле — оператор — значение).
Проанализируем такой вариант кода:
ГДЕ
(ЧекККМ.СтатусЧекаККМ = ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Архивный)
ИЛИ ЧекККМ.СтатусЧекаККМ = ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Пробитый))
Хотя этот вариант является рабочим, в сообществе разработчиков 1С за ним закрепилась репутация «не самого удачного решения». Это связано с тем, как СУБД (особенно MS SQL Server) строит план выполнения запроса — здесь поможет инструмент анализа планов выполнения СУБД. Использование множественных ИЛИ в некоторых сложных запросах может сбить оптимизатор с толку, что приведет к полному сканированию таблицы (Index Scan) вместо быстрого поиска по индексу (Index Seek).
В реальной разработке жесткое кодирование (hardcode) значений перечисления прямо в тексте запроса считается не самым лучшим тоном, если логика фильтрации может измениться. Гораздо профессиональнее передавать массив нужных значений в качестве параметра.
Давайте посмотрим, как это реализовать по шагам:
Пример кода на языке 1С (удобно использовать консоль запросов): — для этого подойдет многофункциональная консоль запросов и кода.
// Формируем список нужных статусов
МассивСтатусов = Новый Массив;
МассивСтатусов.Добавить(Перечисления.СтатусыЧековККМ.Архивный);
МассивСтатусов.Добавить(Перечисления.СтатусыЧековККМ.Пробитый);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЧекККМ.Ссылка
|ИЗ
| Документ.ЧекККМ КАК ЧекККМ
|ГДЕ
| ЧекККМ.СтатусЧекаККМ В (&МассивСтатусов)";
Запрос.УстановитьПараметр("МассивСтатусов", МассивСтатусов);
РезультатЗапроса = Запрос.Выполнить();
Преимущества данного подхода:
&МассивСтатусов окажется пустым, запрос просто не вернет строк, не вызывая при этом критических ошибок выполнения.Рассмотрим техническую сторону вопроса. Когда мы пишем В (&Список), платформа 1С транслирует это в SQL-оператор IN (...). Большинство современных систем управления базами данных отлично оптимизируют такие конструкции.
Если же мы используем ИЛИ, особенно в сочетании с другими сложными фильтрами или соединениями таблиц, СУБД может выбрать неоптимальный план. Это критически важно для высоконагруженных систем. В стандартах разработки 1С рекомендуется избегать ИЛИ в секции ГДЕ, если условие можно переписать через оператор В или через объединение нескольких запросов (ОБЪЕДИНИТЬ ВСЕ).
Выясним также нюанс работы с виртуальными таблицами. Если бы мы делали отбор не в документе, а в виртуальной таблице регистра (например, РегистрНакопления.Продажи.Обороты), то условие на статус обязательно нужно передавать в параметры виртуальной таблицы. Это позволит СУБД отсечь ненужные данные еще на этапе предварительного расчета итогов, а не после выборки огромного массива записей.
В ситуациях, когда список значений для фильтра очень велик (например, сотни или тысячи элементов), использование оператора В может замедлиться. В таких случаях мы рекомендуем использовать временные таблицы:
ЧекККМ) с этой временной таблицей по полю статуса.Для СУБД соединение двух таблиц по индексированным полям зачастую является самой быстрой операцией. Это гарантирует, что поиск будет выполнен максимально эффективно.
Подводя итог, можно сказать: для простых задач используйте конструкцию В (ЗНАЧЕНИЕ(...), ЗНАЧЕНИЕ(...)), а для более гибких и производительных решений — передачу массива через параметры запроса.