记录一次问题排查

1. 问题描述:早上刚来上班,业务部门同事反应管理后台无法登录

2. 问题排查定位

 2.1 服务器排查

  a. 接口是否可以调通:首先自己登陆后台,发现时好时坏,偶尔接口返回【系统忙】。我们系统接口异常调不通会返回系统忙

  b. 服务是否死掉或者假死:连接服务器->查看Java进程,服务正常;排除假死:重启该服务,接口依然调不通

  c. 服务器各项指标:登录阿里云->云服务器ECS->监控,查看CPU、内存、系统负载、云盘iops、网络带宽、连接数,各项指标使用率均在正常范围

 2.2 数据库排查

  a. 数据库各项指标:登录阿里云->云数据库RDS->监控与报警,查看CPU、内存、磁盘空间、iops、网络带宽、连接总数,其它指标正常,唯独CPU使用率达到100%

  b.一键诊断:登录阿里云->云数据库RDS->自治服务->一键诊断,发现CPU使用率偏高,出现了异常慢SQL

    

  c. 慢日志:日志管理 -> 慢日志明细 ,发现有SQL语句耗时7~8分钟,甚至20~30分钟。一条SQL语句执行20多分钟!!!

  d. sql分析:

      

SELECT you.nick_name,you.mobile,ycu.createtime,ycu.id,ycu.ym_userid, ycu.`status`,cir.coupon_name,cir.use_price,if(ycu.status = '1',ycul.createtime,'') as usedtime,cir.coupon_type as couponType, cir.price,cir.province,ycu.end_time 
from ym_coupon_user ycu 

LEFT JOIN ym_org_user you on ycu.ym_userid = you.id 

LEFT JOIN coupon_issue_record cir on ycu.coupon_issue_record_id = cir.id 

LEFT JOIN ym_coupon_used_log ycul on ycu.id = ycul.ym_coupon_user_id 

where 1=1 and you.platform_code ='lngpt' 

order by ycu.createtime desc 

limit 10

  可以看出是四表联查,如果有数据量比较大的表,然后关联字段又没有索引将会非常耗时

  用explain分析,即在SQL语句前加上关键字 EXPLAIN然后执行:

  可以看出,4个表中主表全盘扫描,第2、3表关联字段有唯一索引只扫描一行,但是第4张表也进行了全盘扫描。上图是测试环境,数据量较小。

  线上数据表1和表4分别由10多万条和4万多条!然后关联字段没有加索引,导致查询异常慢。

  给表4的关联字段添加索引(ym_coupon_user_id) 后执行EXPLAIN:

  

  可以看出,表4(ycul)也用上了索引,只取出了一行。到此问题得以解决,一条查询语句耗时由20多分钟优化到0.16秒~

 3. 总结:多表关联查询,如果数据量较大查询太慢,被驱动表的关联字段要加索引。

SQL语句剖析:

对比加索引前后的 EXPLAIN 结果分析:

1. ycu表在ycul表未加索引前使用了临时表 (using temporary)

2. ycul表未加索引是:Using where; Using join buffer (Block Nested Loop),加了索引后是:Using where 

关键字:using temporary、Using join buffer (Block Nested Loop)、Using filesort

下面分别进行解析:

问题1.为啥会出现临时表

答案:用非驱动表字段排序会出现临时表

  关于左关联查询:首先分驱动表和被驱动表,先去驱动表查询数据,然后以此数据为基准去查询被驱动表。

  驱动表和被驱动表的选择受MySQL优化器的控制,这个比较复杂:

  a、没其它条件的话,选择结果集小的作为驱动表

  b、优先以order by字段所在的表作为驱动表,即时该表结果集较大

  c、即使符合上面的条件,优化器还会优先选择关联字段有索引的表作为 被驱动表

  d、都有索引,则不一定会选择order by字段的表作为驱动表,此时如果数据量差距大选择数据量小的为驱动表,如果数据量差距不明显则选择order by字段的表为驱动表

 **** 到此,上面那条SQL语句就可以明白了,我们再分析下 EXPALIN ,为了方便查看我把SQL语句和EXPLAIN再复制一遍:

SELECT you.nick_name,you.mobile,ycu.createtime,ycu.id,ycu.ym_userid, ycu.`status`,cir.coupon_name,cir.use_price,if(ycu.status = '1',ycul.createtime,'') as usedtime,cir.coupon_type as couponType, cir.price,cir.province,ycu.end_time 
from ym_coupon_user ycu 

LEFT JOIN ym_org_user you on ycu.ym_userid = you.id 

LEFT JOIN coupon_issue_record cir on ycu.coupon_issue_record_id = cir.id 

LEFT JOIN ym_coupon_used_log ycul on ycu.id = ycul.ym_coupon_user_id 

where 1=1 and you.platform_code ='lngpt' 

order by ycu.createtime desc 

limit 10
 

  首先,当ycul表关联字段没加索引时,表ycu和表ycul都没有索引,虽然order by ycu.createtime,但ycu和ycul数据量差别很大,所以小表ycul被优化器选为驱动表。

  而此时order by ycu.createtime,即排序字段在非驱动表上,迫使MySQL使用了临时表,结果可想而知。

  当给ycul的ym_coupon_user_id加上索引,则优化器选择了ycu为主表,order by字段在主表,就没有临时表了。

 问题2. 什么时候会使用 join buffer

  …………待续

 问题3. 何时出现 Using filesort

  当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”

  

stay hungry stay foolish!
原文地址:https://www.cnblogs.com/shog808/p/15091072.html