SQL Server的WHERE条件"短路评价"大杀器CASE WHEN
博客专区 > Q_J 的博客 > 博客详情
SQL Server的WHERE条件"短路评价"大杀器CASE WHEN
Q_J 发表于2年前
SQL Server的WHERE条件"短路评价"大杀器CASE WHEN
  • 发表于 2年前
  • 阅读 77
  • 收藏 7
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

摘要: WHERE 快速条件 or 慢速条件,执行时,当"快速条件"已经true时,后面的"慢速条件"还会被继续执行吗?理想的就是不被执行,即遵循"短路评价”方式, short circuit evaluation。 N年来我都回避了这个问题,最近不得不直面这个问题,于是在SQL Server 2012上作了调查,结论是和条件是否利用了表函数有关系。 顺便还证实了CASE WHEN语法里的条件绝对是短路评价,这在MSDN文档里明确有说明,这个东西可以用来提高速度。

可惜证据文档取不出来,而且冗长,就大致做个备忘录,有心的人看看就明白了。


1. 条件里没有子查询 -> 短路评价

SELECT * FROM test WHERE some_fast_check()=1 OR some_slow_check(c) = 1

2. 条件里有子查询,但子查询是针对真实表的 -> 准“短路评价”

SELECT * FROM test WHERE some_fast_check()=1 OR c IN (SELECT * FROM normal_or_temp_table)

需要注意的是:子查询一定会最先执行,相当于先做成一个内存表,勉强说得过去,但是万一这个子查询很慢,偏偏第一个条件已经满足了的时候,那就悲剧了,拖累了整个速度

的确,如果第一个条件满足的话,这之后对于形成的内存表进行Scan的次数=0,所以说这是准 “短路评价”。


3. 条件里有子查询,且使用了“表函数” -> 开始失去控制了。

SELECT * FROM test WHERE some_fast_check()=1 OR c IN (SELECT * FROM some_slow_data())

尤其是上述例子里“标量函数”和“表函数”混合的,是最超乎想象的,这时,

some_slow_data()表函数一定最先被执行一次以便其产生内存表,这个只好忍了。

但是这之后就不可忍了!对于这个内存表,总会被进行N次Scan,而N显然取决于主表里符合其他条件的件数。

就是说就算所有行的some_fast_check()=1已经为true了,这后面针对内存表的Scan还是继续做!

傻啊。没办法,从Plan看就是这样的,SQL Server就是这么任性。

当然,结果速度快不快,还要取决于优化器否决定并发执行,有时也不慢。


4. 短路评价大杀器"CASE WHEN"

例如把下面这句整体当做一个表达式来评价时,当"快速条件"满足了时,整个表达式就出结果(1)了,"慢速条件"都不会被执行,

CASE WHEN 快速条件 THEN 1 WHEN 慢速条件 THEN 1 ELSE 0 END

于是,整个SQL改成:

SELECT * FROM test WHERE 
    CASE WHEN some_fast_check()=1 THEN 1
         WHEN c IN (SELECT * FROM some_slow_data()) THEN 1
         ELSE 0
    END = 1

就可以变快了。


 

还有,不知道DB为什么没有默认开启RECOMPILE选项,这个选项会减少哪些不必要的子查询。

测试时,必须注意用dbcc命令清楚缓存,具体的命令一查就行。

另外一个确定的经验是,IN换成EXISTS或者TABLE JOIN的方式在第一次执行时(没有缓存),Plan是一样的,后来有了Cache之后,TABLE JOIN方式就快些。

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 12
博文 66
码字总数 54682
×
Q_J
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: