В практике разработки на платформе 1С:Предприятие часто возникает задача фильтрации данных в регистрах по конкретному типу документа-регистратора. На первый взгляд, существует несколько способов добиться этого, но какой из них будет наиболее производительным и правильным с точки зрения архитектуры СУБД? Рассмотрим подробнее два основных варианта, которые часто вызывают споры среди разработчиков: использование оператора ССЫЛКА и конструкции ВЫРАЗИТЬ.
Этот вариант является классическим и наиболее рекомендуемым. Синтаксис выглядит следующим образом:
ГДЕ
Взаимодействия.Регистратор ССЫЛКА Документ.CRM_ПредпринятоеДействие
Проанализируем, что происходит внутри системы при выполнении такого запроса. Поле Регистратор является составным типом данных. В физической таблице базы данных (например, MS SQL Server) это поле представлено несколькими колонками: идентификатором типа (обычно числовое поле) и самой ссылкой (GUID). Когда мы используем конструкцию ССЫЛКА, платформа 1С преобразует это в простейшее сравнение идентификатора типа в SQL-запросе.
Преимущества данного метода:
NULL и Неопределено в таких условиях, не вызывая аварийного завершения запроса.Иногда разработчики пытаются применить «хитрый» способ проверки через приведение типа, аргументируя это (зачастую ошибочно) более высокой скоростью работы. Условие выглядит так:
ГДЕ
НЕ ВЫРАЗИТЬ(Взаимодействия.Регистратор КАК Документ.CRM_ПредпринятоеДействие) ЕСТЬ NULL
Разберем по шагам логику этого метода. Платформа пытается привести значение Регистратор к конкретному типу. Если тип совпадает, возвращается ссылка, если нет — возвращается NULL. Затем условие проверяет, не является ли результат приведения пустым.
Выясним причину, почему этот метод может считаться менее эффективным. На уровне SQL-запроса ВЫРАЗИТЬ часто транслируется в конструкцию CASE WHEN... THEN... ELSE NULL END. Для выполнения такого условия СУБД вынуждена вычислять результат выражения для каждой строки таблицы. Это увеличивает нагрузку на процессор сервера и, в большинстве случаев, исключает эффективное использование индексов (происходит Index Scan вместо Index Seek).
Хотя в некоторых специфических сценариях (например, из-за особенностей кэширования плана запроса или устаревшей статистики) этот вариант может показать случайное преимущество в скорости на короткой дистанции, в долгосрочной перспективе на больших объемах данных он неизбежно проиграет.
Рассмотрим еще один возможный, но наименее эффективный вариант:
ГДЕ
ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.CRM_ПредпринятоеДействие)
Проанализируем ситуацию: функция ТИПЗНАЧЕНИЯ в запросе — это тяжелая операция. Она требует получения информации о типе объекта, что на уровне SQL превращается в еще более сложные конструкции, чем в случае с ВЫРАЗИТЬ. Замеры производительности показывают, что этот метод работает медленнее всех остальных и категорически не рекомендуется для использования в секции ГДЕ.
В ходе обсуждения часто поднимается вопрос о динамических фильтрах. Посмотрим на пример кода, который считается «антипаттерном»:
ГДЕ
ВЫБОР
КОГДА &Фильтр = "ТипНоменклатуры"
ТОГДА Номенклатура.ТипНоменклатуры = &ТипНоменклатуры
КОГДА &Фильтр = "ВидНоменклатуры"
ТОГДА Номенклатура.ВидНоменклатуры = &ВидНоменклатуры
ИНАЧЕ ИСТИНА
КОНЕЦ
Почему это работает медленно? Оптимизатор СУБД не всегда может заранее определить, какую ветку ВЫБОР нужно использовать, и строит универсальный (неоптимальный) план запроса. Чтобы решить эту проблему, рекомендуется использовать динамическое конструирование текста запроса на языке 1С.
Разберем решение этой задачи через подстановку параметров или текста:
ТекстЗапроса = "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура ГДЕ ИСТИНА %Условие%";
Если ЗначениеЗаполнено(ТипНоменклатуры) Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "%Условие%", "И ТипНоменклатуры = &ТипНоменклатуры");
КонецЕсли;
Такой подход позволяет передать в СУБД максимально простой и прозрачный SQL-код, который будет гарантированно использовать нужные индексы.
Проанализировав все способы проверки типа Регистратор, мы можем сделать следующие выводы:
ВЫБРАТЬ), чтобы ограничить количество соединений при обращении через точку к реквизитам составного типа. Использование её в ГДЕ избыточно и потенциально вредно для производительности.NULL. Оператор ССЫЛКА обрабатывает это безопаснее всего.Соблюдение этих простых правил позволит вашим запросам работать стабильно и быстро даже при значительном росте объема данных в информационной базе.