暴风雨前夕
前几天晚上,客户反映网站某个功能页面打开缓慢,半天都在加载没有返回结果。用户体验极差。接到消息之后马上起来排查问题,先浏览器查看接口返回,是一个查询接口引起的全是Timeout。后面上服务器TOP命令一瞧 CPU占用率及高,MySQL的占用达到了300%
show processlist
进入mysql 输入show full processlist
显示大量的Query语句 且每个语句耗时都已经几百上千,这所有的SQL语句都来自同一个SQL
SELECT count(1) FROM task_log WHERE task_id = getParentId(68251) and log_type =2
初看没看出什么问题,但是执行EXPLAIN语句之后看出了问题所在。此条SQL没有命中索引,导致全表扫描,预计执行行数300W以上。这可把我惊呆了,我明明在task_id字段上加了索引,为什么没有命中呢。
解决
仔细看了这条SQL语句 我预计是自定义函数getParentId 出了问题,getParentId这个函数是根据树结构的子节点ID获取父节点ID,单独拿出来执行没有任何问题。可一旦拿到上面那条语句就没有命中索引。所以我猜测是使用了自定义函数返回结果作为查询 导致没有命中索引。
原因找到了,解决就好解决了,我立即修改了java代码 sql语句,通过先把父节点ID计算出来再做查询。编译代码覆盖线上环境,重启MySQL(目的在于现在很多慢查询堵在哪里,影响了后续业务无法进行),大功告成。
解决之后的CPU占用情况,一切正常