一次慢查询语句的问题定位及解决方案
2018-02-26 11:19
204 查看
问题现象:
前几天在项目上线过程中,发现有一个页面无法正确获取数据,经排查原来是接口调用超时,而最后发现是因为SQL查询长达到20多秒而导致了问题的发生。复杂SQL语句的构成:
类比的语句来描述当时的场景,可以表达如下:SELECT * FROM a_table AS a LEFT JOIN b_table AS b ON a.id=b.id WHERE a.id IN ( SELECT DISTINCT id FROM a_table WHERE user_id IN (100,102,103) GROUP BY user_id HAVING count(id) > 3 )1)关联查询 从上面简化的SQL语句,可以看出,首先进行的是关联查询。2)子查询 3) 其次,是嵌套的子查询。此子查询是为了找出多个用户共同拥有的组ID。所以语句中的“100,102,103”是根据场景来定的,并且需要和后面“count(id) > 3”的个数对应。简单来说,就是找用户交集的组ID。
耗时在哪?假设现在a_table表的数据量为20W,而b_table的数据量为2000W。大家可以想一下,你觉得主要的耗时是在关联查询部分,还是在子查询部分?(思考空间。。。。)(思考空间。。。。)(思考空间。。。。)
问题定位
初步断定,首先,对于只有一个用户ID时,我会把上面的语句简化成:SELECT * FROM a_table AS a LEFT JOIN b_table AS b ON a.id=b.id WHERE user_id IN (100)所以,初步断定应该是嵌套的子查询部分占用了大部分的时间。再进一步验证既然定位到了是嵌套的子查询语句的问题,那又要分为两块待排查的区域:是子查询本身耗时大,还是嵌套而导致慢查询?结果很容易发现,当我把子查询单独在DB中执行时,是非常快的。所以排除。剩下的不言而喻,20秒的慢查询是嵌套引起的。但因为处于上线紧急的过程中,为了确保,我快速地验证了我的结论:1、将子查询的ID单独执行,并把得到的结果序列手动拼成一段ID,如:1,2,3,4, ... , 9992、将上面得到的序列ID,手动替换到原来的SQL语句3、执行,发现,很快!只用了约150 msWell Done! 准备修复上线!
解决方案
线上的问题,很多时间都是在定位问题和分析原因,既然问题找到了,原因也找到了,解决方案不言而喻。代码简单处理即可。另外一个需要注意的点
因为b_table比a_table大,所以一开始 b_table 左关联 a_table 时,很慢,大概是1秒多,而且数据量是很少的;但若反过来,a_table 左关联 b_table 时,则很快,大概是100毫秒。所以,又发现一个有趣的现象:大表 左关联 小表,很慢;小表 左关联 大表,很快。当然,这些我们理论上都知道,但实际开发会忘却。又或者一开始两个表都为空时,而又没考虑到后期这两个表增长的速度时,日后就会埋下坑了。总结
嵌套的子查询是很慢的。大表左关联小表很慢,小表左关联大表,很快相关文章推荐
- jdbc查询语句中in后传参数问题的解决方案
- 记一次mysql语句因为字符优先级的问题引起的查询结果不一致问题
- oracle中查询和定位数据库问题的SQL语句
- 在一个千万级的数据库查寻中,如何提高查询效率?分别说出在数据库设计、SQL语句、java等层面的解决方案。
- 服务器一次问题查询
- 多音字按拼音首字母排序sql语句的问题解决方案
- 由于查询语句中日期的格式引起的问题
- Java路径问题最终解决方案—可定位所有资源的相对路径寻址
- zend framework2 查询语句数据库不同的问题
- Hql语句模糊查询‘like’与中文问题
- 今天遇到一个问题,linq语句的写法,查询动态字段
- IO--常用的IO问题查询语句
- Ibatis insert语句中包含子查询问题
- VC++2005下的ADO SQL语句(like,count,distinct)和操作表过程中的一些问题的解决方案
- 解决SQL语句中含有中文字符无法查询问题
- Google App Engine平台下JDOQL查询报异常的问题解决方案
- 记一次SSH登陆失败问题的定位
- 关于Hibernate 查询语句中文乱码问题的解决
- MySQL字符集中文乱码终极解决方案和mysql查询中文问题解决方法[转贴]
- “Oracle 9i/Oracle 10g” 查询 参数java.util.date 性能慢的问题和解决方案