前段时间,某个深夜,突然接到项目的告警电话,项目运行异常,查看告警信息是由于项目数据库CPU使用率接近100%导致的。为此深夜中忙活了一阵,当个教训,且记录一次。
现象:服务数据库CPU使用率接近100%,一直居高不下。
原因:SQL语句使用不合理的索引,导致数据库中大量数据的排序,大数据量的记录排序消耗尽CPU,出现慢查询,导致服务告警。
具体分析如下:
select
id, msg_title, msg_type, status, msg_time,.........
from msg
where
(
is_deleted = 0
and status = 0
and mall_id = 909942
and importance = 1
and is_latest = 1
)
order by
msg_time desc
limit 0, 1
id, msg_title, msg_type, status, msg_time,.........
from msg
where
(
is_deleted = 0
and status = 0
and mall_id = 909942
and importance = 1
and is_latest = 1
)
order by
msg_time desc
limit 0, 1
如上是出现问题的sql语句,相关的辅助日志显示,sql的explain执行计划是先做order by 排序,然后执行where条件筛选,和预期的执行顺序不符。预期mysql查询优化器会先执行where条件做筛选,筛选掉大部分数据后,在执行order by做少量数据的排序。出现该现象的分析认为,查询语句使用了msg_time字段索引先做排序(msg_time建有索引), 全表千万级别的表数据量排序必然消耗大量的CPU资源,而且大数据量的排序必然出现慢查询,这才导致CPU消耗居高不下。
改进方式:
分析业务需求后,其实可以使用主键id代替msg_time作为order by的字段,问题消除。