先用vmstat 1看cs和%sy:cs>10000/s或%sy>30%说明锁争用或调度问题;wa低%us高才指向计算密集型SQL;再查INFORMATION_SCHEMA.PROCESSLIST定位Sending data等高CPU状态,结合慢日志中Rows_examined大的语句交叉验证。

怎么确认是慢查询在烧CPU,而不是系统或锁干扰
别一看到top里mysqld占100%就冲进数据库——先用vmstat 1看cs(上下文切换)和%sy(内核态CPU):
• cs > 10000/s 或 %sy > 30%,说明大量线程在抢锁或调度,不是SQL本身慢,而是并发失控或MDL锁被卡住
• wa很低但%us很高,才真正指向计算密集型SQL(比如大表排序、无索引JOIN)
• 如果SHOW PROCESSLIST里全是Sleep,高CPU可能来自InnoDB后台线程(purge、刷脏页),得查SHOW ENGINE INNODB STATUS
用INFORMATION_SCHEMA.PROCESSLIST抓实时“凶手”
比SHOW PROCESSLIST更准,能过滤+排序+看完整状态:
• 执行SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND != 'Sleep' AND TIME > 30 ORDER BY TIME DESC LIMIT 20
• 重点盯State列:Sending data(正在返回结果集)、Sorting result(内存排序中)、Creating sort index(建临时索引)——这些都在猛吃CPU
• INFO字段常被截断,如果看到疑似问题SQL,用SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = [id]单独查完整语句
• 如果一堆线程卡在Waiting for table metadata lock,立刻去查谁在HOLD锁:SELECT * FROM performance_schema.threads WHERE PROCESSLIST_COMMAND = 'Query' AND PROCESSLIST_TIME > 60
慢查询日志不是等它“慢了再看”,而是要设对阈值并关联执行计划
默认long_query_time = 10基本没用,线上建议设为2甚至1:
• 动态开启:SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; SET GLOBAL log_queries_not_using_indexes = ON;
• 日志路径用SHOW VARIABLES LIKE 'slow_query_log_file'确认,别默认写到/tmp下被清理掉
• 别只扫日志找“慢”,要挑出Rows_examined极大(比如>50000)且Query_time不长的语句——这种往往是高频小慢SQL,积少成多拖垮CPU
• 对每条可疑SQL,立刻在库上跑EXPLAIN FORMAT=TRADITIONAL,紧盯type(ALL或index危险)、rows(接近表总行数就是全表扫描)、key(为NULL说明索引失效)
kill命令用错反而让CPU更稳不住
直接KILL [id]干掉连接,应用层重连风暴会让CPU二次飙升:
• 优先用KILL QUERY [id],只中断当前语句,连接保持,避免连接池重建开销
• 只杀State = 'Sending data'且TIME > 60的线程——它们大概率在扫大表或排序,杀完CPU通常秒降
• 如果发现全是Locked状态,别杀SQL,先查SELECT * FROM information_schema.INNODB_TRX找最长事务,再KILL那个事务ID
• 紧急时调大tmp_table_size和max_heap_table_size(比如到512M),能减少磁盘临时表,缓解CPU压力,但别动innodb_buffer_pool_size——调小会加剧IO,调大会触发内存抖动
真正卡点在于:PROCESSLIST只能看到“正在发生什么”,而慢日志记录的是“已经发生过什么”。两者必须交叉验证——比如某条SQL在日志里Query_time=1.8但Rows_examined=80万,再去看PROCESSLIST里有没有同结构SQL正卡在Sorting result,才能断定这是CPU热点。


















