条件查询的性能注意事项(搜索表单)

时间:2014-11-13 21:54:42

标签: sql-server sql-server-2008

我经常发现存储过程的代码如下:

SELECT columns
FROM table_source
WHERE 
    (@Param1 IS NULL OR Column1 LIKE @Param1)
AND (@Param2 IS NULL OR Column2 = @Param2)
AND (@Param3 IS NULL OR ISNULL(Column3,'') LIKE @Param3 + '%')
…

这是否比这样的更好:

WHERE 
    (Column1 LIKE COALESCE(@Param1, Column1))
AND (Column2  = COALESCE(@Param2, Column2))
AND (ISNULL(Column3,'') LIKE COALESCE(@Param3 + '%', ISNULL(Column3, '')))
…

如果我拉出仅依赖于参数的表达式

,这是否重要?
DECLARE @Param3Search nvarchar(30);
SET @Param3Search = @Param3 + '%';

然后使用@Param3Search代替@Param3

很抱歉提出这么广泛的问题,但我确信有一些一般的经验法则可以用来编写这样的查询。我在这方面找不到现有的问题。

3 个答案:

答案 0 :(得分:4)

关于此主题的权威性文章与Dynamic Search Conditions in T-SQL

相关联

您的问题被标记为SQL Server 2008.如果您至少在SP1 CU5上,那么您可以利用"参数嵌入优化"行为作为动态SQL的替代方案。

SELECT columns
FROM   table_source
WHERE  ( @Param1 IS NULL
          OR Column1 LIKE @Param1 )
       AND ( @Param2 IS NULL
              OR Column2 = @Param2 )
       AND ( @Param3 IS NULL
              OR ISNULL(Column3, '') LIKE @Param3 + '%' )
OPTION (RECOMPILE); 

将在每次调用时重新编译,并能够考虑该执行的实际变量/参数值。

暂时假设所有人都是NOT NULL。该计划将编译为

SELECT columns
FROM   table_source
WHERE  Column1 LIKE @Param1
       AND Column2 = @Param2
       AND ISNULL(Column3, '') LIKE @Param3 + '%' 

(我可能会看看是否扩展了Column3上的谓词也导致了更好的计划)

现在假设它们都是NULL。该计划应该简化为

SELECT columns
FROM   table_source

这可能比动态SQL方法更易于维护,并且意味着缓存中可能的单个使用计划更少,但会产生额外的重新编译开销。

答案 1 :(得分:2)

我通常使用动态SQL来实现此目的。

像......这样的东西。

DECLARE @Param1 [DataType]
DECLARE @Param2 [DataType]
DECLARE @Param3 [DataType]

DECLARE @SQL NVARCHAR(MAX);


SET @SQL = N'SELECT columns FROM table_source  WHERE 1 = 1 '
           + CASE WHEN @Param1 IS NOT NULL 
                THEN N' AND Column1 LIKE @Param1 '        ELSE N' ' END
           + CASE WHEN @Param2 IS NOT NULL 
                THEN N' AND Column2 = @Param2 '           ELSE N' ' END
            + CASE WHEN @Param3 IS NOT NULL 
                THEN N' AND Column3 LIKE @Param3 +''%'' ' ELSE N' ' END 

EXECUTE sp_executesql @SQL
                    ,N'@Param1 DataType, @Param2 DataType, @Param3 DataType'
                    ,@Param1
                    ,@Param2
                    ,@Param3

其他方法(@Param2 IS NULL OR Column2 = @Param2)的问题是Sql Server不会像这样短路查询。即使参数为null,它仍然可以继续并尝试计算表达式Column2 = @Param2。

因此,使用动态sql,您可以根据变量构建查询,然后仅使用where where子句执行查询。

在存储过程中使用Dynamic sql还可以为存储过程提供参数化执行计划。

使用您当前的方法参数嗅探将从非常简单的查询中获取性能。

故事的道德:坚持使用这些可选参数的动态sql并使用sp_executesql系统存储过程(保护您免受SQL注入攻击),更好的性能和更少的硬件为您的SQL服务器。

答案 2 :(得分:1)

我会选择使用COALESCE而不是ISNULL,但在大多数情况下,之间的性能会相同,但是T-SQL本身可能就是问题,如果我们使用ISNULL,它就会变得毫无疑问。

请参阅:http://www.mssqltips.com/sqlservertip/2689/deciding-between-coalesce-and-isnull-in-sql-server/