在T-SQL中使用IF会削弱还是破坏执行计划的缓存?


20

有人向我建议,在t-SQL批处理中使用IF语句会降低性能。我试图找到一些确认或验证此断言。我正在使用SQL Server 2005和2008。

断言是以下批处理:

IF @parameter = 0
 BEGIN
  SELECT ... something
 END

ELSE
 BEGIN
  SELECT ... something else
 END

SQL Server无法重新使用生成的执行计划,因为下一次执行可能需要其他分支。这意味着SQL Server将基于执行当前可以确定需要哪个分支的基础,从执行计划中完全消除一个分支。这是真的吗?

另外在这种情况下会发生什么:

IF EXISTS (SELECT ....)
 BEGIN
  SELECT ... something
 END

ELSE
 BEGIN
  SELECT ... something else
 END

无法提前确定执行哪个分支的地方?



1
SQL Server可以并且确实可以重用执行计划,因为它不考虑分支,仅考虑分支中包含的语句。
MartinC 2011年

Answers:


10

SQL Server通过忽略存储过程内部的条件分支来优化存储过程查询计划的编译过程。计划将基于首次执行所使用的参数生成,如果分支的参数不同,则会导致问题。

我将每个分支的SQL放入它们自己的存储过程中,以便生成的计划基于该分支的参数的实际用法。


6

唯一的捷径将是 IF 1 = 1

@parameter和EXISTS都仍然需要处理“一般情况”(@parameter = 42例如)

这样说... 实际执行计划说什么以及探查器捕获重新完成事件?(我不喜欢按照Jao的回答估算的计划)


3

尝试显示估计的执行计划,而不是实际的。您将看到第一个包含COND运算符。

该运算符也包含在缓存的执行计划中。在您的示例中,估计的执行计划将包含一个COND运算符和2个SELECT分支,因此将完全可重用。因为在执行批处理时,SQL Server不仅会评估DML语句,还会评估所有其他语句,因此请从计划中获取它们。

内部执行计划的结构类似于表达式树。


0

计划将基于传递的参数来创建,因此实际上我会说不-具有通常基于参数的条件逻辑不会损害性能。

假设参数引起足够的差异以使查询优化器注意到,您将获得多个计划。

您可以通过打开“显示执行”计划并运行脚本来查看哪个计划-注意计划中的差异。当您运行过程时(我在这里假设存储过程为例),您会注意到第一次通常更快,第二次命中使用了存储计划。更改参数并重复然后运行原始参数-理论上,该计划仍将保留在高速缓存中,但它确实取决于服务器的使用情况(高速缓存滴答声-它们不会永远保留..)等。


0

也许它在2005年和2008年得到了改进,但是在2000年使用条件语句的情况可能比您描述的要糟,它将编译一个计划以最好地处理该过程的第一次运行,然后即使在有条件的情况下也可以使用该计划执行该过程改变了。以我的经验,这导致查询在几分钟之内就可以在几个小时内运行。尽管我现在使用的是2008,但使用过的却是2005,但由于我不再使用它们,因此我无法评论其用法。


2
2005+具有重新编译的语句级别,因此您不再需要“每秒钟一个计划”
gbn
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.