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