mysql cpu高时,应先用show processlist定位非sleep状态的长执行查询,再开启慢日志捕获低频高耗时sql,结合explain分析执行计划,最后用pt-duplicate-key-checker清理冗余索引。

查 SHOW PROCESSLIST 看实时活跃连接在干啥
MySQL CPU 高,八成是某几个查询卡在执行中,而不是空转。直接连上 MySQL 执行 SHOW PROCESSLIST,重点看 State 列不是 Sleep 的行,尤其是状态为 Sending data、Copying to tmp table、Sorting result 的——这些往往是全表扫描或大排序的信号。
实操建议:
- 加
WHERE Command != 'Sleep'过滤掉闲置连接:SELECT * FROM information_schema.PROCESSLIST WHERE Command != 'Sleep' ORDER BY Time DESC LIMIT 10 - 注意
Time值:持续几十秒以上的,基本就是罪魁祸首 - 记下对应
Id,必要时用KILL <code>Id中止(先确认非核心业务) - 如果大量连接卡在
Locked或Waiting for table metadata lock,说明有长事务或 DDL 正在阻塞,不是慢查询本身的问题
开 slow_query_log 抓真·慢查询
光看实时连接不够,很多慢查询一闪而过,或者频率低但单次耗时极长。必须打开慢日志,让 MySQL 主动记录。
实操建议:
- 临时开启(无需重启):
SET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 1(设为 1 秒,别用默认 10 秒) - 确认日志路径:
SELECT @@slow_query_log_file,通常在/var/lib/mysql/xxx-slow.log - 别只依赖
long_query_time:有些查询逻辑简单但锁等待久,log_queries_not_using_indexes = ON能抓到没走索引的“伪快查询” - 用
mysqldumpslow -s t -t 10 /var/lib/mysql/xxx-slow.log快速统计最耗时的 Top 10 查询模板
用 EXPLAIN 看懂为什么没走索引
找到慢 SQL 后,EXPLAIN 是唯一能告诉你“MySQL 实际怎么执行”的命令。很多人只扫一眼 type 是 ALL 就关掉,其实关键在细节。
实操建议:
- 对慢 SQL 加
EXPLAIN FORMAT=TRADITIONAL(MySQL 8.0+ 推荐),比默认输出更直白 - 重点盯三列:
type(ALL/index是全扫,range/ref才算合理);key(显示实际用了哪个索引,NULL就是没用);rows(预估扫描行数,远大于结果集就危险) -
Extra出现Using filesort或Using temporary是性能杀手,通常意味着ORDER BY或GROUP BY没命中索引覆盖 - 注意隐式类型转换:比如
WHERE user_id = '123'(字段是INT),会导致索引失效,EXPLAIN里key会变NULL
建索引不是越多越好,pt-duplicate-key-checker 先清冗余
盲目加索引反而拖慢写入、撑大内存、让优化器选错路。MySQL 5.7+ 虽支持索引下推,但冗余索引仍是常见 CPU 高原因——优化器在一堆相似索引里反复计算成本。
实操建议:
- 用 Percona Toolkit 的
pt-duplicate-key-checker --host=localhost扫一遍,它会明确指出哪些索引被另一个完全覆盖(例如(a,b)存在时,(a)就是冗余) - 联合索引顺序不能乱:
WHERE a = ? AND b > ? ORDER BY c,最优是(a,b,c),不是(a,c,b)——EXPLAIN的key_len会暴露是否只用到了前缀 - 小表(
rows )没必要强加索引,全表扫描可能更快;大表 <code>UPDATE/DELETE没WHERE条件或条件无索引,会锁全表并吃满 CPU - 监控
Handler_read_rnd_next:值飙升说明大量随机 IO,大概率是排序或临时表导致,不是索引问题,得调sort_buffer_size或重写 SQL
真正难的不是建索引,是判断“这个查询值不值得为它单独建索引”。线上表字段多、查询组合多,一个索引救不了所有慢 SQL,也别指望靠索引把烂 SQL 变快。










