先看top中us/sy/wa占比:us高说明sql计算耗cpu,sy高需查系统调用或锁竞争,wa高则优先排查磁盘io;再用pidstat定位高cpu的mysql线程,结合performance_schema和pt-query-digest分析真实负载。

top命令里看到mysqld占CPU高,接下来该看什么
先确认是不是mysqld进程本身在吃CPU,而不是系统调度或IO等待假象。执行top -c后,重点看两行:%cpu(s): xx us, yy sy——如果us(用户态)占比高,问题大概率在SQL计算;如果sy(内核态)高,得查系统调用或锁竞争;wa高就别盯着MySQL了,先查磁盘IO。
接着用pidstat -p $(pgrep mysqld) 1 5持续采样,观察每个线程的CPU占用是否集中在少数几个OS线程上。若某OS线程持续90%+,说明它对应MySQL内部某个连接正在干重活。
show processlist返回一堆Sleep,但CPU还是高
这很常见,Sleep状态只是连接空闲,并不代表没负载。真正消耗CPU的可能是后台线程(如InnoDB purge、change buffer merge)或短时高频查询——它们执行快、不留痕迹,processlist抓不到。
- 运行
SELECT THREAD_ID, NAME, PROCESSLIST_USER, PROCESSLIST_HOST, PROCESSLIST_INFO FROM performance_schema.threads WHERE TYPE = 'FOREGROUND' AND PROCESSLIST_COMMAND != 'Sleep',比show processlist更准,能看见刚结束但还没刷新状态的活跃线程 - 查
SHOW GLOBAL STATUS LIKE 'Threads_running',值长期>50说明并发压力大,即使单个SQL不慢,上下文切换和锁竞争也会推高CPU - 执行
SHOW ENGINE INNODB STATUS\G,看SEMAPHORES段是否有大量os_waits,有就说明线程在等锁或资源,不是SQL慢,是争抢导致CPU空转
慢查询日志没记录,但CPU就是下不来
慢查询日志只捕获执行时间超long_query_time的SQL,而CPU高可能来自大量毫秒级但低效的查询,比如没走索引的WHERE status=1扫百万行,每次0.2秒,QPS 200就压满CPU。
这时候要换工具:
- 用
pt-query-digest分析全量general log(需提前开启),它不依赖执行时间阈值,而是按Rows_examined排序,能揪出“快但脏”的SQL - 查
performance_schema.events_statements_summary_by_digest,重点关注SUM_ROWS_EXAMINED / COUNT_STAR比值大的语句——平均扫描行数高,说明索引没被有效利用 - 检查
SHOW VARIABLES LIKE 'innodb_buffer_pool_size',如果远小于数据总大小,频繁刷脏页和读盘会把CPU拖进内核态,表现就是sy高
EXPLAIN显示type=ALL,但加了索引还是没用
索引存在≠被用,常见失效场景比想象中多:
-
WHERE create_time > NOW() - INTERVAL 7 DAY——函数作用于索引列,直接失效;改成WHERE create_time > '2026-08-06'常量才生效 -
WHERE phone = 13812345678——字段是VARCHAR,传入数字会触发隐式转换,索引失效;统一用字符串'13812345678' -
ORDER BY a,b配INDEX(a)——缺b,排序仍要filesort;必须建INDEX(a,b)且WHERE条件覆盖最左前缀 -
SELECT *+LIMIT 100000,10——偏移量太大,MySQL仍要扫描前10万行;改成分页游标(WHERE id > last_id LIMIT 10)
真正卡点往往不在SQL写法,而在统计信息陈旧或数据倾斜——ANALYZE TABLE跑完再看EXPLAIN,有时执行计划就变了。











