mysql如何排查CPU占用过高_mysql慢查询与索引缺失诊断

4次阅读

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

mysql如何排查CPU占用过高_mysql慢查询与索引缺失诊断

SHOW PROCESSLIST 看实时活跃连接在干啥

MySQL CPU 高,八成是某几个查询卡在执行中,而不是空转。直接连上 MySQL 执行 SHOW PROCESSLIST,重点看 State 列不是 Sleep 的行,尤其是状态为 Sending dataCopying to tmp tableSorting result 的——这些往往是全表扫描或大排序的信号。

实操建议:

  • WHERE Command != 'Sleep' 过滤掉闲置连接:select * FROM information_schema.PROCESSLIST WHERE Command != 'Sleep' ORDER BY Time DESC LIMIT 10
  • 注意 Time 值:持续几十秒以上的,基本就是罪魁祸首
  • 记下对应 Id,必要时用 KILL <code>Id 中止(先确认非核心业务)
  • 如果大量连接卡在 LockedWaiting for table metadata lock,说明有长事务或 DDL 正在阻塞,不是慢查询本身的问题

slow_query_log 抓真·慢查询

光看实时连接不够,很多慢查询一闪而过,或者频率低但单次耗时极长。必须打开慢日志,让 MySQL 主动记录。

实操建议:

  • 临时开启(无需重启):SET GLOBAL slow_query_log = ONSET 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 实际怎么执行”的命令。很多人只扫一眼 typeALL 就关掉,其实关键在细节。

实操建议:

  • 对慢 SQL 加 EXPLAIN format=TRADITIONAL(MySQL 8.0+ 推荐),比默认输出更直白
  • 重点盯三列:typeALL/index 是全扫,range/ref 才算合理);key(显示实际用了哪个索引,NULL 就是没用);rows(预估扫描行数,远大于结果集就危险)
  • Extra 出现 Using filesortUsing temporary 是性能杀手,通常意味着 ORDER BYGROUP BY 没命中索引覆盖
  • 注意隐式类型转换:比如 WHERE user_id = '123'(字段是 int),会导致索引失效,EXPLAINkey 会变 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)——EXPLAINkey_len 会暴露是否只用到了前缀
  • 小表(rows )没必要强加索引,全表扫描可能更快;大表 <code>UPDATE/deleteWHERE 条件或条件无索引,会锁全表并吃满 CPU
  • 监控 Handler_read_rnd_next:值飙升说明大量随机 IO,大概率是排序或临时表导致,不是索引问题,得调 sort_buffer_size 或重写 SQL

真正难的不是建索引,是判断“这个查询值不值得为它单独建索引”。线上表字段多、查询组合多,一个索引救不了所有慢 SQL,也别指望靠索引把烂 SQL 变快。

text=ZqhQzanResources