先确认mysqld是否真正在吃CPU:用top按Shift+P排序,观察%CPU高且RES稳定为计算密集型,RES同步涨则缓冲池或临时表失控;%sy高说明锁等待或上下文切换问题。

确认是不是 mysqld 进程真正在吃 CPU
别急着进数据库,先看系统层有没有干扰。执行 top,按 Shift+P 排序,确认占用最高的确实是 mysqld 进程(不是 backup 脚本、logrotate 或 Java 应用)。重点看三列:%CPU 高但 RES(物理内存)稳定,说明是计算密集型查询;如果 RES 也同步暴涨,可能是缓冲池或临时表配置失控。
检查 %sy(内核态 CPU)是否异常高:如果是,大概率是锁等待或上下文切换问题,不是 SQL 本身慢。vmstat 1 看 cs(context switch)是否超 10k/s —— 高于此值说明线程调度压力大,常因连接数暴增或 thread_cache_size 不够。wa(IO wait)很低但 CPU 高,基本排除磁盘瓶颈。
抓出正在“烧 CPU”的活跃 SQL
SHOW PROCESSLIST 默认只显示前 100 行且截断 SQL,不够用。必须执行:
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' AND TIME > 30 ORDER BY TIME DESC LIMIT 20;
重点关注 State 列:Sorting result、Sending data、Creating sort index 是典型 CPU 密集信号;Locked 或 Waiting for table metadata lock 则指向锁争用,得立刻查谁在 hold 锁。
INFO 字段常被客户端截断,优先用 SHOW FULL PROCESSLIST(注意权限),但生产环境可能受限;更稳妥的是结合 performance_schema.threads 查完整语句和线程状态。
区分是慢查询还是高并发导致的 CPU 飙升
先算真实 QPS:SHOW GLOBAL STATUS LIKE 'Questions'; 除以 SHOW GLOBAL STATUS LIKE 'Uptime';。再对比 Threads_running(当前活跃线程数):
- 如果
QPS和CPU曲线同步飙升,大概率是流量突增,需查应用连接池是否泄漏、是否有定时批量任务上线 - 如果
CPU飙高但QPS平稳,甚至Threads_running长期 >30 而 QPS 很低,基本锁定为个别慢 SQL 或锁阻塞 - 高频低耗时查询也可能拖垮 CPU —— 慢日志里
Count高但单次Query_time仅 0.2s 的语句,累积起来一样吃满核
临时止血比重启更关键
杀错线程会引发重连风暴,杀对了 CPU 立刻回落。优先 KILL QUERY [id](不是 KILL [id]),只中断语句不干掉连接。目标是 TIME > 60 且 State 为 Sorting result 或 Sending data 的线程。
别急着调 innodb_buffer_pool_size —— 临时调小反而可能恶化;但可紧急增大 tmp_table_size 和 max_heap_table_size(比如设为 512M),避免排序/分组频繁落盘;同时确认 sort_buffer_size 是否过小,导致反复内存分配。
真正难的是判断“为什么这条 SQL 突然变慢”:统计信息过期、隐式类型转换、索引最左前缀没对齐、优化器误判……这些不会报错,但会让同一条 SQL 在不同时间表现天差地别。


















