T-SQL Where子句案例语句优化(StoredProc的可选参数)

时间:2009-10-08 19:10:39

标签: sql-server tsql query-optimization case where-clause

我一直在和这个人争斗一段时间。我有一个存储过程,它接受3个用于过滤的参数。如果传入特定值,我想对其进行过滤。如果传入-1,请全部给我。

我尝试过以下两种方式:

第一种方式:

SELECT field1, field2...etc  
FROM my_view  
WHERE  
parm1 = CASE WHEN @PARM1= -1 THEN parm1  ELSE @PARM1 END  
AND parm2 = CASE WHEN @PARM2 = -1 THEN parm2  ELSE @PARM2 END  
AND parm3 = CASE WHEN @PARM3 = -1 THEN parm3  ELSE @PARM3 END

第二种方式:

SELECT field1, field2...etc  
FROM my_view  
WHERE  
(@PARM1 = -1 OR parm1 = @PARM1)  
AND (@PARM2 = -1 OR parm2 = @PARM2)  
AND (@PARM3 = -1 OR parm3 = @PARM3)  

我在某处读到第二种方式会短路,如果是真的话,永远不会评估第二种方式。我的DBA说它强制进行表扫描。我还没有对此进行验证,但在某些情况下似乎运行速度较慢。

此视图选择的主表有大约150万条记录,并且视图继续加入大约15个其他表以收集大量其他信息。

这两种方法都很慢......把我从瞬间带到2-40秒的任何地方,这在我的情况下是完全不可接受的。

是否有更好的方法不涉及将其分解为特定vs -1的每个单独案例?

感谢任何帮助。感谢。

5 个答案:

答案 0 :(得分:6)

  

我在某处读到第二种方式会短路,如果是真的话,永远不会评估第二种方式。我的DBA说它强制进行表扫描。

你读错了;它会短路。你的DBA是对的;它不能很好地与查询优化器配合使用,并可能强制进行表扫描。

第一个选择就是它的优点。您可以选择使用过滤器列的每个可能组合来动态sql或长存储过程,以便获得独立的查询计划。您也可以尝试使用“WITH RECOMPILE”选项,但我认为它不会对您有所帮助。

答案 1 :(得分:5)

如果您运行的是SQL Server 2005或更高版本,则可以使用IF使用正确的WHERE创建多个版本的查询,以便可以使用索引。每个查询计划都将放在查询缓存中。

另外,这是一篇关于这个主题的非常全面的文章:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

它涵盖了尝试使用多个可选搜索条件编写查询的所有问题和方法

这是目录:

  Introduction
      The Case Study: Searching Orders
      The Northgale Database
   Dynamic SQL
      Introduction
      Using sp_executesql
      Using the CLR
      Using EXEC()
      When Caching Is Not Really What You Want
   Static SQL
      Introduction
      x = @x OR @x IS NULL
      Using IF statements
      Umachandar's Bag of Tricks
      Using Temp Tables
      x = @x AND @x IS NOT NULL
      Handling Complex Conditions
   Hybrid Solutions – Using both Static and Dynamic SQL
      Using Views
      Using Inline Table Functions
   Conclusion
   Feedback and Acknowledgements
   Revision History

答案 2 :(得分:2)

如果在需要所有内容时传入空值,则可以将where子句写为

   Where colName = IsNull(@Paramater, ColName)  

这与你的第一种方法基本相同......只要列本身不可为空,它就会起作用...空值 IN 列会使它稍微搞乱。

加速它的唯一方法是在Where子句中为要过滤的列添加索引。有没有?如果没有,那将导致显着的改善。

答案 3 :(得分:0)

我无法想到其他方式:

WHERE

(MyCase IS NULL或MyCase = @MyCaseParameter) 和....

如果你问我,第二个对开发人员来说更简单易读。

答案 4 :(得分:0)

SQL 2008及更高版本对(MyCase IS NULL OR MyCase = @MyCaseParameter) AND ....

等内容的优化进行了一些改进

如果你可以升级,并且你为所有可能的param组合添加一个OPTION (RECOMPILE)来获得不错的性能(这种情况下没有一个计划对所有可能的param组合都有好处),你可以发现这很好。

http://blogs.msdn.com/b/bartd/archive/2009/05/03/sometimes-the-simplest-solution-isn-t-the-best-solution-the-all-in-one-search-query.aspx