В SQL часто требуется динамическая фильтрация — например, в отчетах или поиске, когда фильтры задаются пользователем. Основные подходы:
(@param IS NULL OR поле = @param), чтобы лишние условия не влияли на результат, если параметр не задан. Этот способ безопасен, но иногда приводит к неоптимальному использованию индексов.Пример шаблона для поиска заказов:
SELECT * FROM Orders WHERE (@CustomerID IS NULL OR CustomerID = @CustomerID) AND (@Status IS NULL OR Status = @Status) AND (@DateFrom IS NULL OR OrderDate >= @DateFrom) AND (@DateTo IS NULL OR OrderDate <= @DateTo);
Вопрос: Почему иногда ухудшается производительность при использовании подхода (@param IS NULL OR Column = @param) — даже при наличии индекса на Column?
Ответ: Такой шаблон мешает оптимизатору использовать индекс эффективно, так как в условии участвует переменная, и запрос превращается в полноценный скан таблицы вместо индексного поиска. На больших объёмах данных это критично.
Пример:
WHERE (@name IS NULL OR name = @name)
Это условие — не то же самое, что просто name = @name, что не позволяет СУБД легко использовать индекс.
История
В сервисе поиска по клиентской базе внедрили "гибкие фильтры" через шаблон (@par IS NULL OR Field = @par), и при росте объёма заказов скорость поиска упала с секунд до минут — индексы перестали работать, ибо оптимизатор не мог определить конкретное значение.
История
В e-commerce проекте фильтрацию собирали через динамический SQL без параметров, подставляя значения напрямую. Инъекции позволили пользователям получить списки всех клиентов, т.к. фильтр был уязвим — пароли пришлось срочно менять.
История
BI-отчёты строились через параметризованный шаблон без учёта того, что OR-ные условия убирают индексированные сканы. На миллионных наборах отчёты «вставали колом», пока не переписали фильтрацию под оптимальный вариант с обязательными условиями и отдельной логикой по разным комбинациям параметров.