我经常发现存储过程的代码如下:
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
?
很抱歉提出这么广泛的问题,但我确信有一些一般的经验法则可以用来编写这样的查询。我在这方面找不到现有的问题。
答案 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/