从一次客户投诉看SQL语句中IN和EXIST性能上的区别

SQL语句
409
0
0
2022-07-30
标签   SQL优化

O公司财务系统上线之后,用户在填报销单的时候,经常遇到页面打开慢的情况,请供应商来看,答曰一切正常,继续观察。此后,页面打开越来越慢,甚至于达到20多秒才能加载完,来自于全公司的抱怨越来越多,供应商的观察迟迟不见结果。

领导很生气,后果很严重,IT部上下压力极大,鉴于供应商极不给力(此事另提),于是撸起袖子自己上阵搞,开发的兄弟查代码,硬件的兄弟做实时监控,我负责数据库性能优化。

很快有了第一波反馈,问题集中在打开页面调用的一段存储过程上,每次打开页面都要调用此存储过程,时间长达20~30秒。页面代码没问题,但此时服务器CPU/内存使用峰值会达到90%以上,因此必须要优化此存储过程。

这段存储过程比较复杂,内容主要是一个查询语句:

从一次客户投诉看SQL语句中IN和EXIST性能上的区别

供应商的SQL语句

从实现功能角度看,该语句没什么问题,数据量也不算大,我尝试分段运行,速度也在毫秒级,但放在一起执行就要用到20多秒,DBA的直觉告诉我结构上一定有不合理的地方。

在分段运行的时候,我发现有一段子查询SQL的结果集为空,主SQL和子SQL之间用的是EXISTS关键字,一个念头一闪而过,我知道问题出在什么地方了。于是我做了如下修改:

从一次客户投诉看SQL语句中IN和EXIST性能上的区别

改过后的SQL语句

再执行的时候时间缩短到0.5秒以内,问题完美解决。重新部署之后,可以看到系统性能完全正常了。

从一次客户投诉看SQL语句中IN和EXIST性能上的区别

服务器性能图

问题的关键就在于那个EXISTS,由于EXISTS用的是Loop循环匹配,主SQL每一条结果都要在子SQL的结果集中循环,导致子SQL结果集为空的情况下也要占用资源重复运行。此时改成IN,用的是Hash连接,子SQL结果集为空的情况下直接就返回空值,效率因此提升。

后续发生的事让我啼笑皆非,供应商开发经理对此的解释是公司有规定,所有用嵌套查询的地方必须用EXISTS,所以他们查不出问题。听到此,内心瞬间一万只草泥马奔腾而过。

很多程序员都有印象,好像EXISTS比IN的效率高,但却说不出所以然,或曰书上是这样写的,甚至还有如此奇葩的公司把这当成开发规范。我想说,死读书不求甚解害死人啊!