概述今天发现有一个项目应用每次启动都会导致另一个应用服务崩溃,而这两个应用使用同一个数据库。经排查发现是报表应用的某个查询功能引起的,但是咨询开发查不出是哪个SQL,只能靠自己排查了。下面是大概的流程的解决方案。1、打开慢查询修改my.ini配置,添加参数slow-query-log=1slow_query_log_file="epms-slow.log"long_query_time=10,修改后重启,观察epms-slow的内容。日志日志。2、找到慢sql再次点击report模块,选择date点击查询,系统崩溃后,观察日志中涉及的慢查询sql,发现问题sql如下:selectid,parent,project,namefromzentao.zt_taskwhereparent=0/*andexists(selectt.parentfromzentao.zt_tasktwheret.parent>0)*/andidin(selectt.parentfromzentao.zt_tasktwheret.parent>0);3.查看执行计划explainselectid,parent,project,namefromzentao.zt_taskwhereparent=0/*andexists(selectt.parentfromzentao.zt_tasktwhereparent.parent.parent>0)*/andidin(selectt.parentfromzentao.zt_tasktwheret.parent>0);这里可以看到因为是全量扫描,每次扫描50000条,产生了笛卡尔积。50,000*50,000将导致数据库崩溃。4.考虑用exists改写sqlexplainselectid,parent,project,namefromzentao.zt_tasktwhereparent=0andexists(selecta.parentfromzentao.zt_taskawherea.parent=t.id)这里改写后问题依旧没有解决。5.考虑withrewriting后,发现zt_task表查询了两次,于是考虑withrewriting简化,只查了一次WITHtmpAS(SELECT*FROMzt_task)SELECT*FROMtmpt1JOINtmpt2ONt1.id=t2.parent嗯,mysql5.7是这样的不支持withrewriting,mysql8版本才支持,所以这里只能放弃这种方法>0)taONt1.id=ta.parentANDt1.parent=0记得这里去重。改写后,查询可以在1秒内得到结果,满足需求。总结通过这个案例,大家一定要记住,多表查询的性能是很差的。当然,性能不好有个前提:数据量大。子查询=简单查询+有限查询+多表查询+统计查询复杂;之前强调过多的表查询不建议大家使用,因为性能很差,但是替代多表查询最有利的还是子查询,所以子查询(子查询是指在一个查询中嵌套其他几个查询)是实际工作中用的挺多的。
