查不到lock wait事务时,应先确认是否为元数据锁(mdl)阻塞:看到“waiting for table metadata lock”状态,需查performance_schema.metadata_locks定位lock_status='granted'的持锁者和'pending'的等待者,而非依赖innodb_trx或innodb_lock_waits。

查不到 LOCK WAIT 事务?先确认是不是元数据锁堵的
看到 Waiting for table metadata lock 状态,别急着查 INNODB_TRX——那是行锁视图,对不上。元数据锁(MDL)由 DDL 触发,比如 ALTER TABLE、DROP INDEX 正在执行或被阻塞,会卡住所有后续对这张表的读写。这时候 SHOW PROCESSLIST 里能看到状态,但 INNODB_LOCK_WAITS 是空的。
真要定位,得查 performance_schema.metadata_locks:
- 过滤
OBJECT_SCHEMA和OBJECT_NAME找目标表 - 看
LOCK_STATUS = 'PENDING'的请求者,和LOCK_STATUS = 'GRANTED'的持有者 - 再用
THREAD_ID关联performance_schema.threads拿到PROCESSLIST_ID,最后去PROCESSLIST查 SQL
注意:performance_schema 默认可能关闭,SHOW VARIABLES LIKE 'performance_schema' 先确认;开它要重启,线上通常不选这条路。
INNODB_TRX 显示 trx_state='LOCK WAIT',但查不到 blocking_trx_id?
这是典型“锁已释放但事务还没提交”的假象:等待事务刚报错回滚,阻塞它的那个事务还活着、没提交,所以 INNODB_LOCK_WAITS 里查不到记录——因为 InnoDB 只保留当前活跃的等待关系快照。
这时必须倒推:
- 从
INNODB_TRX找出trx_state = 'RUNNING'且trx_started时间异常早(比如 >30 秒)的事务 - 用它的
trx_mysql_thread_id去PROCESSLIST查INFO,看是不是卡在SLEEP、HTTP调用、文件读写等外部操作上 - 如果
INFO为空,说明 SQL 已执行完但事务没COMMIT,重点盯应用层连接池配置和事务边界代码
别信“SQL 执行完了就没事”——InnoDB 锁只在事务提交/回滚时释放,不是语句结束时。
EXPLAIN 显示 type=ALL,但加了索引还是锁全表?
索引存在 ≠ 查询能走索引。常见断点:
-
WHERE条件用了函数,比如WHERE DATE(create_time) = '2026-09-01'→ 索引失效 - 隐式类型转换,比如
user_id是BIGINT,但传参是字符串'123'→ MySQL 自动转类型,放弃索引 - 联合索引顺序错,
INDEX(a,b,c),查询只用WHERE c=1→ 无法命中 - 统计信息过期,
ANALYZE TABLE没跑过,优化器误判走全表扫描
验证方法:在测试库开 optimizer_trace,跑一遍问题 SQL,看 trace 里 chosen_range_access_summary 是否真用了索引,而不是只看 key 字段非空。
KILL 错线程反而让雪崩更猛?
报错日志里写的线程 ID(比如 ERROR 1205 ... thread_id=1234)只是“等锁失败”的受害者,KILL 它毫无意义——锁还在别人手里。真正该 KILL 的是 blocking_trx_id 对应的那个事务。
但要注意两个现实约束:
-
blocking_trx_id在INNODB_LOCK_WAITS里是十六进制字符串(如123456789ABC),要转成十进制,再匹配PROCESSLIST.ID - 如果阻塞方是个长事务(比如批处理),KILL 它可能触发大量回滚,I/O 瞬间拉满,连带拖慢其他业务
更稳妥的做法:先用 SELECT * FROM information_schema.PROCESSLIST WHERE ID = ? 确认它正在执行什么,再决定是 KILL 还是联系业务方协调停机窗口。
行锁等待的根子永远不在数据库参数上,而在事务边界是否清晰、索引是否真正生效、应用是否把网络调用塞进了事务里——这些地方漏掉一个,innodb_lock_wait_timeout 调成 1 秒或 300 秒,都只是把雪崩延迟几秒,或者让它炸得更碎。











