先确认mysqld进程本身是否真在消耗CPU,执行top -p $(pgrep mysqld)并按Shift+P排序,重点看%us(>70%为SQL计算密集)、%sy(>30%为锁或调度问题)、%wa(高则说明IO瓶颈);再查information_schema.PROCESSLIST中command!='Sleep'且time>10的活跃SQL,关注Sorting result等状态及索引失效特征。

确认是不是 mysqld 真正在吃 CPU
别急着进数据库,先看系统层有没有干扰。执行 top -p $(pgrep mysqld),按 Shift+P 排序,确认占用 CPU 最高的确实是 mysqld 进程本身,而不是 backup 脚本、logrotate 或某个 Java 应用在假扮 MySQL。
重点看 %us(用户态)和 %sy(内核态):
- 如果 %us > 70%,基本锁定是 SQL 计算密集型问题
- 如果 %sy 异常高(比如 > 30%),可能是大量锁等待或上下文切换,不是 SQL 本身慢,而是线程调度卡住了
- 如果 %wa 很高,说明在等磁盘 IO,CPU 高是“伪高”,得查磁盘或 buffer 配置
快速抓出刚上线就在烧 CPU 的活跃 SQL
新部署实例没多少历史慢日志,slow_query_log 可能还没来得及记录——必须实时抓正在执行的语句。执行:
SELECT id, user, host, db, command, time, state, info FROM information_schema.PROCESSLIST WHERE command != 'Sleep' AND time > 10 ORDER BY time DESC LIMIT 20;
重点关注:
- state 是 Sorting result、Sending data、Creating sort index 的,大概率是没走索引的 ORDER BY / GROUP BY / COUNT(*)
- info 字段里出现 IN () 且括号为空,或者 LIKE '%xxx',基本就是索引失效现场
- 多个线程同时卡在 Locked 或 Waiting for table metadata lock,说明有 DDL 正在执行(比如刚建完表就立刻查),不是慢查询,是元数据锁阻塞
检查是否因配置突变或初始化行为触发
新实例常踩的坑不是代码,而是默认配置和首次加载行为:
- 检查 innodb_buffer_pool_size 是否过小(比如只设了 128M),导致频繁刷脏页和读盘,CPU 被内核态调用拖高
- 执行 SHOW VARIABLES LIKE 'binlog%';,如果 log_bin 开启但磁盘空间不足,binlog 写失败会引发后台线程反复重试,CPU 持续打满
- 查看 performance_schema 是否被启用(performance_schema = ON),新实例若误开且未调优,采集开销本身就能吃掉 10%~20% CPU
- 检查是否有定时任务(如 Quartz)在部署后立即触发,批量执行无索引的 COUNT(*) 或大范围 UPDATE
临时止血:不重启也能让 CPU 回落
KILL 是最快的降载方式,但必须 kill 对线程:
- 优先 kill state = 'Sending data' 且 time > 60 的线程,它们通常在扫全表或做大排序,持续消耗 CPU
- 用 KILL QUERY [id](不是 KILL [id]),只中断当前语句,保留连接,避免应用重连风暴
- 如果发现是某个业务用户(如 app_user)的连接集中爆发,可临时限制其并发:ALTER USER 'app_user'@'%' WITH MAX_USER_CONNECTIONS 5;
- 别碰 innodb_buffer_pool_size:新实例 buffer pool 还没预热,此时调小反而引发更多物理读,CPU 更高
新部署实例的 CPU 飙升,往往不是某条 SQL 多慢,而是多个“看起来合理”的动作叠加——比如刚导入百万数据、自动收集统计信息、应用启动时批量预热查询、又开了 binlog + performance_schema —— 它们各自开销都不大,合起来就把 CPU 压穿了。盯住 PROCESSLIST 和 top -H -p $(pgrep mysqld) 的线程级分布,比查慢日志更管用。


















