SHOW PROCESSLIST 可快速识别高CPU SQL:重点检查State为Sending data等且Time>30秒的Query线程,结合EXPLAIN分析;并发锁等待则需统计Locked/Updating线程并查INNODB STATUS。

如何用 SHOW PROCESSLIST 快速识别高CPU SQL
MySQL 自身不直接暴露 CPU 占用,但活跃的、未优化的查询会持续持有线程、扫描大量行、频繁锁表,间接导致 mysqld 进程 CPU 暴涨。SHOW PROCESSLIST 是第一道筛子,重点看 State 和 Time 两列:
-
State为Sending data、Copying to tmp table、Sorting result且Time> 30 秒,大概率是全表扫描或大结果集排序 -
Command是Query(非Sleep),Info显示SELECT ... JOIN ... WHERE ...但没走索引,要立刻复制该 SQL 做EXPLAIN - 避免只看
Id或User—— 同一应用用户可能跑几十个正常短查询,真正危险的是单条执行超 2 分钟的慢查询
为什么 top 里看到 mysqld CPU 高,但 PROCESSLIST 没明显长查询?
常见于并发堆积场景:单条 SQL 不慢,但几百个线程同时争抢同一张热表的行锁或间隙锁,State 显示为 Updating 或 Locked,Time 持续增长。此时 PROCESSLIST 里可能有大量状态相似的线程,Info 是同一条 UPDATE/DELETE 语句。
- 用
SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE State IN ('Locked', 'Updating') AND Time > 10;统计锁等待线程数 - 结合
SHOW ENGINE INNODB STATUS\G查TRANSACTIONS部分,找lock struct(s)和阻塞源头事务 ID - 注意:MySQL 8.0+ 的
performance_schema.data_locks表可直接查当前锁,比INNODB STATUS更精准
top -Hp $(pgrep mysqld) 找出具体线程后,怎么关联到 SQL?
Linux 线程 ID(LWP)和 MySQL 的 Id 并不一致,不能直接对应。正确路径是:先用 top -Hp 定位占用 CPU 最高的线程 PID,再通过 /proc/<pid>/stack</pid> 看内核栈,确认是否在 InnoDB 行查找或 B+ 树遍历路径上;然后回到 PROCESSLIST,按 Time 降序,优先检查最近刚变 Running 状态的那几条。
- 不要尝试用
strace -p <pid></pid>跟踪 mysqld 线程 —— 开销极大,可能让实例雪崩 - 如果
stack显示大量row_search_for_mysql或btr_cur_search_to_nth_level,基本锁定是索引失效导致的深度遍历 - MySQL 5.7+ 可开启
performance_schema+events_statements_current表,用THREAD_ID关联 OS 线程 ID(需提前开启setup_actors)
临时止损:杀掉异常线程前必须确认的三件事
盲目 KILL <id></id> 可能引发主从延迟、事务回滚风暴或连接池耗尽。执行前务必交叉验证:
- 查
SELECT * FROM information_schema.PROCESSLIST WHERE ID = <id>\G</id>,确认Command是Query且Info不为空(空 Info 可能是内部线程,KILL 有风险) - 用
SELECT USER, HOST, DB FROM information_schema.PROCESSLIST WHERE ID = <id>;</id>判断是否来自关键业务 IP 或库 - 检查
SHOW GLOBAL STATUS LIKE 'Threads_running';,如果值 > 200 且持续上涨,说明问题已扩散,应先限流(如 ProxySQL 规则拦截该 SQL 模式),而非单点 KILL
最常被忽略的是:某些“慢查询”实际是备份工具(mysqldump、mydumper)或监控脚本触发的全库 SELECT COUNT(*),这类请求 Info 可能被截断,需结合 Host 和连接时间综合判断。


















