<p>最直接的方式是查sys.innodb_lock_waits表,它聚合底层锁信息、免JOIN、一行展示等待与阻塞双方关键字段(如waiting_pid、blocking_pid、waiting_query、wait_age_secs等),执行SELECT * FROM sys.innodb_lock_waits ORDER BY wait_age_secs DESC LIMIT 5可快速定位当前最久的5个锁等待,但该视图仅反映瞬时状态,锁释放即消失,需实时查询。</p>

直接查 sys.innodb_lock_waits 看谁在等、谁在堵
这是最直给的入口:它把等待方和阻塞方拼成一行,不用手动 JOIN。执行 SELECT * FROM sys.innodb_lock_waits ORDER BY wait_age_secs DESC LIMIT 5 就能立刻看到当前最久的 5 个锁等待。
wait_age_secs 是关键字段——不是时间戳,是已等待秒数,>30 秒基本要介入;但它只反映采样瞬间状态,锁一释放记录就消失,所以必须在卡顿发生时实时查。
-
waiting_query为空?别跳过,说明事务只BEGIN没执行语句,得用waiting_pid去SHOW PROCESSLIST查Info列 -
blocking_pid为NULL?常见于隐式事务(比如应用断连后没 COMMIT),这时要往下查INNODB_TRX+PROCESSLIST -
sql_kill_blocking_query字段给出的是可直接执行的KILL语句,但先别急着跑,确认阻塞源是否真可杀
联合 INNODB_TRX 和 PROCESSLIST 找“Sleep 却 RUNNING”的悬挂事务
很多锁等待根源不是活跃 SQL,而是应用连接池归还了连接但没 COMMIT。这种事务在 PROCESSLIST 里是 Command = 'Sleep',但在 INNODB_TRX 里仍是 trx_state = 'RUNNING',一直霸着锁。
必须用 JOIN 查,单查 INNODB_TRX 会漏掉:
SELECT t.trx_id, t.trx_started, t.trx_state, p.ID, p.USER, p.HOST, p.COMMAND, p.TIME, p.INFO FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE p.COMMAND = 'Sleep' AND t.trx_state = 'RUNNING' ORDER BY t.trx_started;
-
TIME > 300且INFO为空 → 极大概率是应用异常中断或忘记COMMIT -
trx_isolation_level = 'REPEATABLE READ'→ 即使只执行过一次SELECT,事务启动就持 MDL 锁 - 别只看
trx_mysql_thread_id,要结合p.HOST和p.USER定位到具体服务实例
遇到 Waiting for table metadata lock 得切到 sys.schema_table_lock_waits
这个状态说明不是行锁问题,而是 DDL(如 ALTER TABLE)被 SELECT 或长事务阻塞了元数据锁(MDL)。此时 sys.innodb_lock_waits 会完全沉默——它只管 InnoDB 行级锁。
查它:SELECT * FROM sys.schema_table_lock_waits\G
-
blocking_lock_type = 'SHARED_READ'?大概率是个没提交的普通查询在 hold 表级读锁 - 返回为空?先确认
performance_schema已启用(SELECT @@performance_schema应为 1),且采集器开了:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl' -
blocking_pid为NULL不代表没锁,可能是隐式事务或空闲连接持锁,得回退查performance_schema.metadata_locks
innodb_lock_wait_timeout 不是解药,设错反而坏事
这个参数只控制“等多久就报错”,不解决“为什么等”。默认 50 秒,调成 5 秒只会让报错更快,但阻塞依旧存在。
- 临时排查可设高点:
SET innodb_lock_wait_timeout = 120,避免误判为超时而非真卡死 - 永久修改写进
/etc/my.cnf前必须验证:有些 ORM 对短超时有重试逻辑,改小可能引发雪崩式重试 - 它只影响行锁等待(DML),对 DDL 的元数据锁无效——后者由
lock_wait_timeout控制 -
SET GLOBAL只对新连接生效,已连的老连接不会变,这点极易踩坑
真正卡住你的,往往不是慢 SQL,而是那个你根本没注意到的、挂着 Sleep 状态却一直 RUNNING 的事务。


















