cpu飙高需先区分用户线程或系统线程:若top显示mysqld占用高但show processlist多为sleep,则问题在innodb后台线程,常见于innodb_log_file_size过小导致redo频繁刷盘,或innodb_buffer_pool_size太小致缓存命中率低;若出现copying to tmp table或sorting result状态,则是排序/聚合等计算型cpu消耗,需检查执行计划是否含using filesort/using temporary;高频轻量查询、n+1问题、连接池配置不当及过严刷盘参数(如innodb_flush_log_at_trx_commit=1)也易引发cpu无声爬升。

CPU飙高不等于SQL慢,先看是用户线程还是系统线程在吃资源——这是定位根因的第一道分水岭。
top里看到mysqld占CPU高,但show processlist全是Sleep
这说明问题不在前台查询,而在InnoDB后台线程。常见于innodb_log_file_size过小导致redo log频繁刷盘,或innodb_buffer_pool_size太小造成缓存命中率低(比如低于95%)。
- 执行
show engine innodb status\g,重点看log capacity used是否接近100%,以及buffer pool hit rate是否明显偏低 - 检查当前配置:
show variables like 'innodb_log_file_size';、show variables like 'innodb_buffer_pool_size'; - 默认值往往不够用:比如
innodb_log_file_size=48M(双文件共96M),在写密集场景下几秒就满;innodb_buffer_pool_size=128M对千万级表基本无效 - 调整需重启生效,且
innodb_log_file_size变更前必须停库+清空日志文件,否则启动失败
show processlist里出现大量Copying to tmp table或Sorting result
这是典型计算型CPU消耗,不是I/O瓶颈。MySQL正在内存或磁盘上做临时排序、聚合、去重等操作。
-
state字段比info更关键:即使SQL看起来简单,ORDER BY或GROUP BY没走索引也会触发临时表 - 用
EXPLAIN确认执行计划:type为ALL或index、Extra含Using filesort/Using temporary即为风险信号 - 避免在WHERE条件中对字段做函数操作,例如
WHERE DATE(create_time) = '2026-08-01'会让索引失效 - 大结果集分页慎用
LIMIT 100000, 20,改用游标式分页(如WHERE id > last_id ORDER BY id LIMIT 20)
慢查询日志里没多少记录,但CPU还是高
可能被高频轻量查询打满,比如单条QPS几千的点查,每条只耗0.1ms,但累加起来压垮CPU。
- 启用性能模式监控:
SELECT THREAD_ID, SQL_TEXT, TIMER_WAIT FROM performance_schema.events_statements_summary_by_digest ORDER BY TIMER_WAIT DESC LIMIT 10; - 关注
count_star字段——如果某条SQL执行次数极高(比如每秒几百次),即使avg_timer_wait很低,总耗时也惊人 - 检查应用层是否存在N+1查询:ORM中循环调用
findById()比一次findAllByIds()多出几十倍网络和解析开销 - 连接池配置不当也会加剧:
maxActive设得过大,导致大量并发线程争抢CPU调度,而非真正执行SQL
真正卡点往往藏在配置与行为的交界处:比如innodb_flush_log_at_trx_commit=1保障了数据安全,但在高并发写入时强制刷盘,会把CPU拖进内核态;又比如query_cache_type=1在MySQL 5.7后已废弃,若误开启反而增加锁竞争。这些细节不报错,但会让CPU使用率无声爬升。











