首页 > 其他 > 详细

性能优化实战-join与where条件执行顺序

时间:2017-07-26 19:01:13      阅读:371      评论:0      收藏:0      [点我收藏+]

昨天经历了一场非常痛苦的性能调优过程,但是收获也是刻骨铭心的,感觉对sql引擎的原理有了进一步认识。

问题起源于测试人员测一个多条件检索的性能时,发现按某个条件查询会特别慢。对应的sql语句简化为:

 

[sql] view plain copy
 
 print?
  1. select * from ta a,tb b  
  2. where a.bid=b.id  
  3. and a.col1=‘xx‘  
  4. and b.col2=‘yy‘  
  5. and dbo.func(a.col3,‘zz‘)=1  

 

ta表几万行,tb几百行。

大家看到了,慢的那个条件就是"and dbo.func(a.col3,‘zz‘)=1". 这里用到自定义函数是迫不得已的,原因暂且不表。所以当qa只用a.col3查的时候,需要遍历ta表,对每一行应用函数,不慢才怪 呢。由于a.col3不是主要条件,qa就不跟我纠结这个问题了。但是qa又用b.col2和a.col3一起查询,最终结果才几十条,为什么还是非常慢。我说sql估计还是先全表执行了那个函数,所以还是慢。qa说无法接受,然后提了个bug。

其实我也非常纳闷,为啥sql引擎会制定出那么sx的执行计划,明明先用b.col2过滤,再做表连接,再去用函数过滤,该多好?!没办法,我只好耐下心来,研究执行计划。

看了计划发现,ta条件和tb的条件是并行过滤的,过滤完之后再做连接。我开始考虑,能不能做点什么,让sql按想要的步骤来走。于是:

1. 在a.col1上加了索引,发现没啥提升,原来a.col1=‘xx‘并没有过滤掉多少数据。

2. 在b.col2上加了索引,也没提升,依然是函数执行完毕后才连接。

3. 在a.col3上建索引?a.col3是个复杂文本,建索引没有任何意义。

4. 把写法改为join,并且把各个条件在on和where之间来回倒腾,没用。

5. 想把函数加个with schemabinding, 但放弃了,这个函数的性能其实已经到极限了,指定架构的话,怕是没什么提升,而且又加了额外的限制,不妥。

6. 想加一个undocument的查询提示,不让它并行过滤。既然select末尾加上OPTION (QUERYTRACEON 8649)可以强制并行,那我把8649换成其他数字能强制不走并行吗?换了好几个,都没用。后来才发现,这个querytraceon的并行和本文的并行没有半毛钱关系。

7. 使用嵌套查询。加一层select * from,把func条件提到外层来。按道理,func应该最后过滤了吧!结果,还是一样的执行计划。我是该夸sql engine太智能呢,还是该骂它太sb呢?

8. 准备在代码里动手脚,结果代码冻结了……只准改sql。

manager说今天必须搞定,不然影响今天发包。

黔驴技穷。四面楚歌。

无计可施了,我只能做点边边角角的事情,想把整体性能再弄好一点,比如,许多重要的索引在当前的新库上都没建好,于是我就一个个补上去,其中包括a.bid上的索引。这时候,奇迹发生了,那个很慢的查询突然变得飞快!!!在那一刻,我顿悟了,为什么之前一直是最后才进行表连接?因为sql engine啃不动func这个东西,连接条件上又没有索引,所以只好按常规套路,先执行各表的过滤条件,尽量让待连接的行数减到最小,最后再做关联。

至此,问题解决:)

总结一下:

1. 关联字段上的索引非常重要。

2. 把条件放在(inner)join-on或者where后面,以及条件的先后顺序,对效率影响不大(仅针对Sqlserver)。但我个人习惯是,两表连接条件放在join-on后面,各表自己的过滤条件放在where后面,尊重语义,易读易维护。

性能优化实战-join与where条件执行顺序

原文:http://www.cnblogs.com/firstdream/p/7241245.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!