mysql 8.0+ 中 innodb_lock_waits 恒为空,应通过 innodb_row_lock_current_waits 初筛锁等待,再用 performance_schema.data_lock_waits 定位阻塞关系,并以 innodb_trx.trx_wait_started 计算实时等待时长。

直接查 INNODB_LOCK_WAITS 表已经没用了——MySQL 8.0+ 中它恒为空,不是你权限或SQL写错了,是官方废弃了。真正能反映“此刻等了多久”的,只有 INNODB_TRX.trx_wait_started 字段。
怎么快速确认当前有没有锁等待
别一上来就 JOIN 多张表。先用开销最低的方式初筛:
-
SHOW STATUS LIKE 'innodb_row_lock_current_waits';返回值 > 0,说明此刻有事务卡在行锁上 - 搭配看
innodb_row_lock_time_avg:若该值突然从几毫秒跳到 50ms 以上,说明等待已成规模,不是偶发抖动 - 这个状态变量普通账号就能查,适合脚本高频轮询(比如每 5 秒一次)
- 注意:它归零 ≠ 问题消失——可能只是锁刚释放,或等待刚好超时(默认
innodb_lock_wait_timeout=50秒)
怎么定位谁在等、谁在挡(MySQL 8.0+ 正确写法)
必须用 performance_schema.data_lock_waits,但它默认不采集数据,得手动开开关:
- 检查锁采集是否启用:
SELECT NAME, ENABLED FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/%';,确保wait/lock/innoDB/lock等项为YES - 打开消费者:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME IN ('global_instrumentation', 'thread_instrumentation'); - 关键查询(注意字段类型!):
BLOCKING_ENGINE_TRANSACTION_ID必须连INNODB_TRX.trx_id,不能误连trx_mysql_thread_id(后者是线程 ID,类型不一致,查不到结果)
SELECT r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_pid,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_pid,
b.trx_query blocking_query
FROM performance_schema.data_lock_waits w
JOIN information_schema.INNODB_TRX b ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID
JOIN information_schema.INNODB_TRX r ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID;
怎么算出“当前等了多久”并用于告警
只看到谁在等不够,得量化等待时长才能判断是否要干预:
- 从
INNODB_TRX表取trx_wait_started(MySQL 5.7+ 引入,类型为DATETIME),再用NOW() - trx_wait_started得到秒级等待时长 - 不要用
innodb_row_lock_time_avg:它是自实例启动以来所有等待的累计平均值,单位毫秒,完全不反映当前某条事务的真实等待 - 示例语句:
SELECT trx_id, trx_mysql_thread_id, trx_query, UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(trx_wait_started) AS wait_seconds FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'LOCK WAIT'; - 结果为空 ≠ 没锁等待,可能只是当前没有事务处于
LOCK WAIT状态(比如刚释放、或已超时回滚)
为什么 MyISAM 根本没法监控锁等待耗时
MyISAM 没事务、没行锁、没等待队列。它的“锁”是表级的、阻塞式的、不可中断的。所谓“等待”,其实是操作系统层面的线程挂起,MySQL 不记录任何等待开始时间。
-
SHOW OPEN TABLES WHERE In_use > 0返回的表,只表示该表正被某个线程打开并持有读/写锁——但你无法知道这个锁持有了多久、谁在等、等了多久 -
In_use=1对 MyISAM 表甚至可能只是个简单SELECT,不代表有问题 - 监控重点不是“耗时”,而是
Key_reads / Key_read_requests比值——超过0.01就说明key_buffer_size不够,索引缓存失效导致频繁磁盘读,间接拖慢所有操作











