SHOW PROCESSLIST可实时查看正在执行的慢SQL,重点关注State为Sending data等、Time超5秒的连接;需启用slow_query_log并设long_query_time≤1,结合Rows_examined分析真实CPU消耗源。

查当前正在跑的慢SQL:用 SHOW PROCESSLIST 快速抓活口
CPU飙高时,最直接的线索就是“此刻正在干啥”。SHOW PROCESSLIST 不查日志、不等采样,立刻看到所有连接在执行什么语句、卡在哪一步、跑了多久。
- 重点关注
State列为Sending data、Copying to tmp table、Sorting result的行——这些不是简单查询,是真正在消耗CPU的重操作 -
Time值大于 5 秒的,基本可判定为异常;若大量连接Time持续增长,说明查询堵住了,可能锁表或索引失效 - 别只看
root用户,应用连接池常用固定账号(如app_user),要盯住实际业务用户下的长时连接 - 注意:
SHOW PROCESSLIST默认只显示本用户会话,加WITH FULL(MySQL 8.0+)或用SUPER权限才能看到完整列表,否则可能漏掉关键线程
确认慢查询是否被记录:检查并启用 slow_query_log
临时抓到的语句只能反映“此刻”,但CPU飙升往往是周期性或批量触发的。慢查询日志才是回溯根因的证据链。
- 先确认是否开启:
SHOW VARIABLES LIKE 'slow_query_log'—— 返回OFF就白忙,得立刻开 - 开日志本身不耗资源,但
long_query_time设太高(比如默认 10 秒)等于没开:线上建议设为1或0.5,尤其QPS高的实例 - 务必同时打开
log_queries_not_using_indexes:很多“不慢”的查询因没走索引,在高并发下集体压垮CPU,这类语句不会进慢日志,除非显式开启该选项 - 日志路径由
slow_query_log_file决定,别假设它在/var/lib/mysql/下——用SELECT @@slow_query_log_file确认真实位置,避免查错文件
分析慢日志时,别只盯着 Query_time
很多人一看到 Query_time: 2.345s 就去优化这条SQL,结果改完发现CPU还是100%——因为真正吃CPU的,可能是 Rows_examined: 2847391 这种扫描了近三百万行的“伪快查询”。
-
Rows_examined高 +Query_time低 = 典型索引缺失或条件未命中索引,语句本身短,但每秒执行几百次就把CPU拉满 -
Lock_time显著高于Query_time?说明不是CPU问题,是锁争用,得看INFORMATION_SCHEMA.INNODB_TRX和锁等待链 - 用
mysqldumpslow -s t -t 10 /path/to/slow.log聚合统计,但注意:它会把带不同参数的同构SQL(如WHERE id=123和WHERE id=456)合并,掩盖参数化查询的真实分布 - 真正有效的做法是:用
grep "SELECT" slow.log | awk '{print $NF}' | sort | uniq -c | sort -nr | head -20快速揪出高频模板,再结合Rows_examined排序筛选
索引不是万能解药:警惕 CREATE INDEX 引发的写放大
看到 Rows_examined 高就加索引?小心从CPU瓶颈变成IO瓶颈甚至主从延迟爆炸。
- 对写多读少的表(如订单明细、日志类),在
user_id上加索引可能让每次INSERT多写3–4次磁盘(聚簇索引+二级索引+undo+redolog),反而推高CPU和IO -
ALTER TABLE ... ADD INDEX在大表上是阻塞操作(MySQL 5.6+ 支持ALGORITHM=INPLACE,但仍有锁),线上慎用;优先考虑pt-online-schema-change - 复合索引顺序错位(比如
WHERE a=1 AND b>10 ORDER BY c却建了INDEX(a,c,b))会导致排序无法利用索引,CPU依然在内存里归并 - 一个字段上存在多个功能重叠的索引(如
idx_a、idx_a_b、idx_a_b_c),MySQL优化器可能选错执行计划,反而让Rows_examined更高
SHOW PROCESSLIST 看的是现场,慢日志看的是痕迹,而 Rows_examined 才是连接两者的标尺——它不撒谎,但需要你主动去读。










