如果“城市”列上有单独的非聚集索引,那么@Jonathan 提供的答案肯定会提高性能。如果两者都不是,则执行计划将导致 SCAN。如果您有非聚集索引,那么 Jonathan 的方法将执行 SEEK 而不是 SCAN,这在性能方面会很好。
让我尝试用下表中的示例解释为什么会出现这种情况:为了便于使用,我没有考虑两个谓词 dept 和 city,而是只考虑 City。
考虑下面的员工表:
CREATE TABLE [dbo].[Employee](
[EmployeeId] [int] NULL,
[EmployeeName] [varchar](20) NULL,
[Dept] [varchar](15) NULL,
[city] [varchar](15) NULL
) ON [PRIMARY]
GO
--Creating Clustered Index on Id
CREATE CLUSTERED INDEX [CI_Employee_EmployeeId] ON [dbo].[Employee] ( [EmployeeId] ASC)
--Loading Data
加载样本数据
Insert into Employee
Select top (10000) EmployeeId = Row_Number() over (order by (Select NULL))
,EmployeeName = Concat ('Name ',Row_Number() over (order by (Select NULL)))
,Dept = Concat ('Dept ',(Row_Number() over (order by (Select NULL))) % 50)
,City = Concat ('City ',Row_Number() over (order by (Select NULL)))
from master..spt_values s1, master..spt_values s2
现在使用普通谓词执行简单查询:
Declare @city varchar(15) = 'City 1500'
Select * from Employee where city = @city
--It Does Clustered Index Scan
现在在城市上创建一个非聚集索引
--Now adding Index on City
Create NonClustered Index NCI_Employee_City on dbo.Employee (city)
Declare @city varchar(15) = 'City 1500'
Select * from Employee where city = @city
--It Does Index Seek
现在来到你的 isnull 函数
由于它强制对每个城市使用 SCAN,如下所示
Declare @city varchar(15) = 'City 1500'
Select * from Employee where city = isnull(@city, City)
go
Declare @city varchar(15) = 'City 1500'
Select * from Employee where city is null or city = @city
如果您查看整体百分比,则 IsNull 函数需要更多。
因此,如果您有索引,所有这些都会有所帮助,否则无论如何都会被扫描。