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