动态使用“CASE”的类将影响性能

时间:2016-11-28 15:18:30

标签: sql tsql

我有一个名为Employee的表。 字段是

1.EmployeeId, 2.Name, 3.Salary, 4.Address

我需要编写一个程序来获取所有员工的详细信息。此过程的where子句是动态的。我能够编写动态查询来获取详细信息。但我最近探索了以下格式查询。

SELECT * FROM Employee
WHERE 1=1
AND EmployeeId = CASE WHEN @EmployeeId IS NULL  OR LEN(@EmployeeId) =0  THEN EmployeeId ELSE  @EmployeeId END
AND Name = CASE WHEN @Name IS NULL  OR LEN(@Name) =0  THEN Name ELSE  @Name END
...
...
ORDER BY Name ASC

@EmployeeId,@ name来自应用程序

可以告诉我这会对动态查询产生任何性能影响吗?或哪一个表现更好?

where子句条件是动态的。这对2条件并不严格。有时是1或3或4或0

对于任何拼写错误

抱歉

提前致谢。

1 个答案:

答案 0 :(得分:0)

让我们说这是您正在使用的数据:

-- sample data
USE tempdb;
GO
CREATE TABLE dbo.employee (EmployeeId int, Name varchar(100));
INSERT dbo.employee
SELECT TOP (100)
  ABS(checksum(newid())%10)+1, 
  CASE abs(checksum(newid())%3)+1 WHEN 1 THEN 'Peter' WHEN 2 THEN 'Paul' ELSE 'Mary' END 
  + ' ' +
  CASE abs(checksum(newid())%3)+1 WHEN 1 THEN 'Smith' WHEN 2 THEN 'Jones' ELSE 'White' END
FROM sys.all_columns;

-- A good covering index 
CREATE NONCLUSTERED INDEX nc_employee ON dbo.employee (EmployeeId, Name);

首先请注意,您可以使用此查询获得完全相同的结果和执行计划:

SELECT * 
FROM dbo.employee
WHERE (EmployeeId = @EmployeeId OR NULLIF(LEN(@EmployeeId),0) IS NULL)
AND   (Name       = @Name       OR NULLIF(LEN(@Name),0)       IS NULL)

假设存在可用的索引 - 您的查询(或上面的查询)将创建一个基本的执行计划,包括索引搜索或索引扫描,以及SELECT运算符。扫描是否按原样运行查询,如果在任一查询结束时包含OPTION(RECOMPILE),则搜索...索引搜索比扫描要好得多。

使用上述OPTION(RECOMPILE)提示获取索引查找的另一种方法是使用动态SQL,如下所示。

DECLARE @EmployeeId int    = 5,
        @Name varchar(100) = 'Peter White';

DECLARE @sql nvarchar(2000) = N'SELECT * FROM dbo.employee';
DECLARE @ParmDefinition nvarchar(500);
SET @ParmDefinition = N'@EmployeeId int, @Name varchar(100)';

SET @sql += 
CASE 
  WHEN (NULLIF(LEN(@EmployeeId),0) IS NOT NULL AND NULLIF(LEN(@Name),0) IS NOT NULL)
    THEN ' WHERE EmployeeId = @EmployeeId AND Name = @Name;'
  WHEN (NULLIF(LEN(@EmployeeId),0) IS NULL AND NULLIF(LEN(@Name),0) IS NOT NULL)
    THEN ' WHERE Name = @Name;'
  WHEN (NULLIF(LEN(@EmployeeId),0) IS NOT NULL AND NULLIF(LEN(@Name),0) IS NULL)
    THEN ' WHERE EmployeeId = @EmployeeId;'
  ELSE ''
END;

EXECUTE sp_executesql @sql, @ParmDefinition, @EmployeeId = @EmployeeId, @Name = @Name;

最后,值得注意的是,对于@EmployeeID为NULL或空白但@Name具有值的情况 - 您将获得扫描。如果你想在这些情况下进行搜索,你会想要另一个看起来像这样的索引:

CREATE NONCLUSTERED INDEX nc_employee2 ON dbo.employee (Name, EmployeeId);