使where子句虚拟的性能影响 - SQL Server

时间:2017-07-27 08:21:23

标签: sql performance tsql where-clause

我需要了解以下编写查询方法对性能的影响。 假设有一个员工表。要求是获取特定部门下的员工列表,并且可选地,用户可以通过提供城市/位置来过滤结果集。

declare @dept varchar(10) = 'ABC', @city varchar(10) 
select * from employee where dept = @dept and city = isnull(@city, city)

这样好吗?或者我们是否需要使用传统的if逻辑来检查用户是否将城市作为输入?

谢谢,
Sabarish。

3 个答案:

答案 0 :(得分:1)

我记得在某处读过以下语法比调用ISNULL()更快:

select * from employee where dept = @dept and (@city IS NULL OR @city = city)

这有点与SQL编译器有关,知道如果@city为null,它可以忽略括号中的表达式。

很抱歉,但不知道我在哪里读到这篇文章(就在不久前),否则我会引用它。

答案 1 :(得分:0)

解决nulls性能问题的最强大的方法是尽量避免默认值为null。在你的情况下应该尝试类似的东西:

declare @dept varchar(10) = 'ABC', @city varchar(10) = 'unknown' 
SELECT * 
FROM employee 
WHERE dept = @dept AND 
      @city = 'unknown'
UNION
SELECT * 
FROM employee 
WHERE dept = @dept AND 
      city = @city AND 
      @city != 'unknown'

为什么呢? 基数估计器无法估计查询返回的正确行数,并且导致执行计划对此特定查询不利。避免空值,一切都会很棒B - )

答案 2 :(得分:0)

肯定@Jonathan提供的答案可以提高性能,如果城市'列上有单独的NonClustered Index。如果不是,则执行计划都将导致SCAN。如果你有NonClustered Index,那么Jonathan的方法将做SEEK而不是SCAN,这在性能方面会很好。

让我试着解释一下为什么那样的情况如下表所示:为了便于使用,我没有考虑两个谓词部门和城市,而是我只考虑城市。

考虑以下员工表:

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

Clustered Index Scan as no index on city

现在在城市

上创建非聚集索引
--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

Index Seek due to non-clustered index

现在来到你的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 vs or condition

如果你看一下IsNull函数需要更多的整体百分比。

因此,如果你有一个索引所有这些将是有帮助的,否则它将是扫描无论如何。

相关问题