一眼识别阻塞者:先查innodb_trx中trx_state='lock wait'的等待事务,再通过innodb_lock_waits定位其blocking_trx_id,最后用processlist查该id对应线程的info字段sql即为罪魁祸首。

怎么一眼看出谁在卡住别人?
别查慢查询日志,也别翻应用代码——先连上 MySQL,直接跑这三条语句:
-
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'LOCK WAIT':找出正在等锁的事务,记下它的trx_mysql_thread_id -
SELECT * FROM information_schema.INNODB_LOCK_WAITS:拿到blocking_trx_id,它就是真正占着锁不放的那个 -
SELECT * FROM information_schema.PROCESSLIST WHERE ID = ?(把上一步的blocking_trx_id对应的线程 ID 填进去):看到INFO字段里那条 SQL,基本就是罪魁祸首
注意:INNODB_LOCK_WAITS 在 MySQL 5.7 和 8.0 行为一致,但 8.0+ 更推荐用 sys.innodb_lock_waits,字段名更直白,比如直接有 blocking_pid 和 waiting_pid。
为什么 SHOW PROCESSLIST 看不到真正的阻塞者?
SHOW PROCESSLIST 显示的是连接状态,不是锁持有状态。一个事务可能早已执行完 UPDATE,但没 COMMIT,此时线程状态是 Sleep、Time 很大、Info 为空——它不活跃,却死死攥着锁。
- 重点盯
PROCESSLIST里Command = 'Sleep'且Time > 60的行 - 如果对应
INNODB_TRX.trx_query是空的,而trx_state = 'RUNNING',八成就是它 - 别被
State = 'Locked'迷惑——那是 MyISAM 表锁,InnoDB 不会显示这个状态
查到 blocking_query 后该 KILL 谁?
必须 KILL blocking_trx_id 对应的线程,不是报错那个。
- KILL 报错线程只是让当前请求失败,阻塞源还在,下个请求照常超时
- 确认前先看
PROCESSLIST.User:如果是system user,可能是主从复制线程,KILL 会中断同步 - 如果
blocking_query是SLEEP(300)或 HTTP 调用类操作,说明应用层有长事务逻辑缺陷,不是数据库配置问题
innodb_lock_wait_timeout 调大有用吗?
没用,还容易掩盖问题。
- 调成 300 秒,用户得干等 5 分钟才报错,连接池可能先爆了
- 这个参数只对当前会话生效,
SET GLOBAL不影响已有连接 - 它对元数据锁(MDL)完全无效——DDL 阻塞要靠
lock_wait_timeout控制,俩参数不能混
真正卡点往往藏在事务边界不清、索引缺失导致全表扫描加锁、或 FOR UPDATE 没配 WHERE 条件——这些比调参重要得多。











