threads_running是真实并发压力指标,只统计执行sql的线程数,超32需警惕,64+表明cpu或锁已成瓶颈;配合threads_connected可判断连接空闲问题,结合innodb_row_lock_waits等定位长事务与锁争用。

查 SHOW PROCESSLIST 之前先看 Threads_running
很多同学一发现慢,就直奔 SHOW PROCESSLIST,结果满屏 Sleep 状态,误以为“没活干”,其实关键指标早爆了。Threads_running 才是真实并发压力的晴雨表——它只统计正在执行 SQL 的线程数,不是连接数。超过 32(默认值)就值得警惕,64+ 基本说明 CPU 或锁已成瓶颈。
实操建议:
- 用
SHOW GLOBAL STATUS LIKE 'Threads_running'实时查,比翻PROCESSLIST更快更准 - 配合
SHOW GLOBAL STATUS LIKE 'Threads_connected'对比:如果后者远大于前者,说明大量连接空闲,问题可能在应用层未释放连接 - 注意
max_connections设置过高但Threads_running持续卡在 10–20,大概率是慢查询阻塞了后续请求,不是连接池不够
innodb_row_lock_waits 突增?别急着加索引,先看事务边界
innodb_row_lock_waits 每秒涨几十次,第一反应常是“加索引”,但多数时候是事务写得太宽——比如一个 HTTP 请求里开了事务,中间调了三次外部 API,最后才更新数据库。这期间锁一直挂着,别人只能等。
实操建议:
- 查
SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_row_lock_waits',再对比Innodb_row_lock_time_avg:如果平均锁等待时间超 50ms,基本确认是长事务或锁范围过大 - 用
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5找出运行超 2 秒的事务,重点看TRX_QUERY和TRX_STATE - 避免在事务里做日志写入、HTTP 调用、文件读写;UPDATE/DELETE 必须带精确
WHERE条件,禁用无条件全表更新
Handler_read_* 指标暴露了真实扫描成本
SELECT COUNT(*) 很快,但业务查询却慢?Handler_read_next 和 Handler_read_rnd_next 是更真实的“扫描行数”代理指标。前者高说明索引用了但回表多,后者高基本等于全表扫描——哪怕 EXPLAIN 显示走了索引。
实操建议:
- 查
SHOW GLOBAL STATUS LIKE 'Handler_read%',重点关注Handler_read_rnd_next / Handler_read_next比值:> 0.1 就要怀疑覆盖索引缺失 - 对高频查询,确保
SELECT字段都在联合索引里(最左匹配),避免SELECT *或额外字段触发回表 -
Handler_read_first持续增长,说明有大量没走索引的ORDER BY或GROUP BY,需检查是否缺少排序字段索引
磁盘 I/O 不高但响应延迟高?检查 sync_binlog 和 innodb_flush_log_at_trx_commit
云上 MySQL 经常出现「磁盘 util QPS 上不去、query_time 波动大」,问题往往不在磁盘吞吐,而在刷盘策略。这两个参数控制日志落盘时机,直接决定单条事务的最小延迟下限。
实操建议:
-
sync_binlog = 1+innodb_flush_log_at_trx_commit = 1是强一致性组合,但每次事务都触发两次 fsync,SSD 也要 1–2ms,高并发下成为硬瓶颈 - 若业务可接受秒级主从延迟,设为
sync_binlog = 1000+innodb_flush_log_at_trx_commit = 2,性能常提升 3–5 倍 - 切勿在机械盘环境设
innodb_flush_log_at_trx_commit = 0,断电丢数据风险极高;SSD 可考虑,但必须配 UPS
真正卡住性能的,常常不是某条慢 SQL,而是多个看似合理的配置叠加后产生的隐式放大效应——比如长事务锁表 + binlog 强同步 + buffer pool 不足,三者同时存在时,问题表现会掩盖真实根因。盯指标时,永远优先看变化率和比例,而不是绝对值。











