2017-07-27 43 views
0

我需要了解下面的编写查询方法的性能影响。 假设有一张员工表。要求是获取特定部门下的员工列表,并且可以选择通过提供城市/位置来筛选结果集。使where子句dummy虚拟的性能影响 - SQL Server

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

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

谢谢,
Sabarish。

回答

1

我记得读书的地方,下面的语法比调用ISNULL()更快:

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

这是什么做的SQL编译器有效地知道它可以忽略括号内的表达式,如果@city是空值。

对不起,但不知道我在哪里读过(这是前一段时间),否则我会引用它。

0

解决空值性能问题的最强有力的方法是尽量避免默认值的空值。在你的情况应该是这样的:

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)

0

肯定的@Jonathan提供的答案将提高性能,如果'城市'列有单独NonClustered指数。如果不是这两个执行计划都会导致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函数需要更多。

因此,如果你有一个索引,所有这些将是有用的,否则它将被扫描。