innodb_row_lock_current_waits > 5 表示当前存在活跃阻塞,innodb_row_lock_waits > 100/分钟说明锁争用已常态化;需通过 show status like 'innodb_row_lock%' 获取全部5项指标并交叉分析。

直接看 innodb_row_lock_current_waits 和 innodb_row_lock_waits 这两个值,就能快速判断锁竞争是否严重——前者 > 5 表示当前有阻塞,后者 > 100/分钟说明事务设计或热点行已成瓶颈。
如何查这组指标:SHOW STATUS LIKE 'innodb_row_lock%'
执行这条命令即可获取全部 5 个关键计数器:
SHOW STATUS LIKE 'innodb_row_lock%';
输出中重点关注以下五项(单位均为整数,非累计百分比):
-
innodb_row_lock_current_waits:当前正在等待行锁的事务数。> 5 就该立刻排查,> 20 基本确认存在活跃阻塞链 -
innodb_row_lock_waits:自上次重启以来发生的锁等待总次数。单独看没意义,要换算成“每分钟发生次数”——若 > 100/分钟,说明锁争用已常态化 -
innodb_row_lock_time_avg:平均每次锁等待耗时(毫秒)。> 50ms 暗示索引失效或查询范围过大,不是慢 SQL 就是锁粒度失控 -
innodb_row_lock_time_max:历史最长单次锁等待(毫秒)。> 1000ms 要结合INNODB_TRX找出具体卡住的事务 -
innodb_row_lock_time:锁等待总耗时(毫秒)。除以 QPS 后若 > 1000ms/秒QPS,说明锁开销已吞噬有效吞吐
为什么不能只盯一个指标
这些值必须交叉验证,孤立看会误判:
-
innodb_row_lock_current_waits突然归零,但innodb_row_lock_waits持续飙升 → 可能是短事务高频争抢,而非长事务挂起 -
innodb_row_lock_time_avg很低,innodb_row_lock_time_max却极高 → 存在偶发性热点行(比如 status = 'pending' 的订单队列表) -
innodb_row_lock_waits高但innodb_row_lock_current_waits始终为 0 → 锁等待时间极短,可能只是并发 INSERT 冲突,不需紧急干预
真正危险的组合是:innodb_row_lock_current_waits > 5 且 innodb_row_lock_time_avg > 50ms —— 这通常意味着某条 UPDATE 正在反复锁住同一行或间隙。
查到异常后下一步该做什么
指标报警只是信号灯,真问题藏在事务和锁关系里:
- 立即执行
SELECT * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT',找出被阻塞的事务及其TRX_WAITING_LOCK_ID - 在 MySQL 8.0+ 中,用
SELECT * FROM performance_schema.data_locks查谁持有了对应锁;5.7 则依赖已废弃的INNODB_LOCKS(注意兼容性) - 通过
SELECT * FROM information_schema.INNODB_LOCK_WAITS直接看到“谁在等谁”,包括阻塞事务 ID 和被锁资源 - 重点检查
TRX_QUERY字段里的 SQL —— 90% 的问题出在没走索引的WHERE条件,比如UPDATE task_queue SET QState = 2 WHERE QState = 1(QState无索引就等于全表扫+全表锁)
别急着优化 SQL,先确认是不是定时任务在固定时间点批量唤醒大量相似事务——比如每分钟更新 200 万行中的“待处理”状态,这才是根因。











