WHERE子句不按逻辑顺序进行过滤

Ami*_*ian 2 t-sql sql-server isnull sql-server-2008

我正在编写一个通用搜索存储过程来基于用户可以在UI中选择的许多过滤器(使用MS-SQL 2008)在表中进行搜索.

这是简化版:

CREATE PROCEDURE SearchAll
    @FirstName NVARCHAR(MAX) = NULL,
    @LastName NVARCHAR(MAX) = NULL,
    @Age INT = NULL
AS
    SELECT * 
    FROM persons 
    WHERE 
        (@FirstName IS NULL OR FirstName = @firstname)
        AND (@LastName IS NULL OR LastName = @LastName)
        AND (@Age IS NULL OR Age = @Age)
Run Code Online (Sandbox Code Playgroud)

似乎如果我将NULL传递给@Age,那么就没有性能成本.但是,当我测试大量数据时,我失去了很好的性能!

这里的查询是相同的逻辑但实际上非常不同:

DECLARE @FirstName NVARCHAR(MAX) = NULL
DECLARE @Age INT = 23
------------First slow------------
SELECT * 
FROM persons 
WHERE 
    (@FirstName IS NULL OR FirstName = @firstname)
    AND (@Age IS NULL OR Age = @Age)
------------Very fast------------
SELECT * 
FROM persons 
WHERE 
    Age = @Age
Run Code Online (Sandbox Code Playgroud)

错过了一点吗?

我知道SQL引擎找到索引的最佳匹配,并且......(在运行查询之前),但很明显:@FirstName IS NULL并且不需要分析任何东西.

我还在ISNULL查询中测试了函数(相同的结果).

Rem*_*anu 5

包含此构造的查询@variable is null or @variable = column是性能灾难.这是因为SQL计划已创建,因此它们适用于变量的任何值.有关该主题的冗长讨论,问题和可能的解决方案请参阅T-SQL中的动态搜索条件