死锁检测是主动探测机制而非超时,innodb_deadlock_detect关闭后事务循环等待将依赖innodb_lock_wait_timeout超时回滚,导致无法区分真死锁与慢锁等待,且show engine innodb status不显示死锁信息。

死锁检测不是“超时”,而是被主动关闭了
MySQL 的 innodb_deadlock_detect 是个开关,不是超时参数。它控制的是「是否启用死锁主动探测机制」。设为 OFF 后,InnoDB 就不再主动扫描事务等待图、不再触发死锁回滚——此时若真发生循环等待,事务会一直卡在锁等待状态,直到触发 innodb_lock_wait_timeout 报错(ERROR 1205 (40001)),看起来像“死锁检测超时”,其实是根本没检测。
什么时候会关掉 innodb_deadlock_detect
极少数高并发短事务场景下,有人为降低 CPU 开销而手动关闭它:
- 每秒数万级 UPDATE/DELETE 且行锁冲突频繁,InnoDB 死锁检测的图遍历开销可能占到 CPU 10%+(尤其在 OLTP 热点行争抢时)
- 业务能接受“用锁等待超时兜底”,且已通过应用层重试 + 事务拆分规避真实死锁
-
innodb_lock_wait_timeout已调小(如设为 5 秒),让卡住的事务快速失败,避免长等待拖垮连接池
但注意:关闭后无法区分「真死锁」和「单纯慢锁等待」,所有循环依赖都得靠超时硬等,排查难度陡增。
SHOW ENGINE INNODB STATUS 里看不到死锁信息
如果 innodb_deadlock_detect=OFF,即使发生循环等待,SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK 区域永远为空——因为根本没做检测。你只能看到:
- 大量事务处于
LOCK WAIT状态 - 等待链(
---TRANSACTION ... waiting for lock...)持续存在,不自动中断 - 最终报错是
Lock wait timeout exceeded,而非明确的Deadlock found
这时候别翻死锁日志,先查变量:SELECT @@innodb_deadlock_detect;。返回 OFF 就坐实了问题根源。
关掉之后,innodb_lock_wait_timeout 变得更关键
原来死锁检测会在毫秒级发现并回滚一个事务;关掉后,所有锁冲突都退化成纯等待,超时时间就成了唯一逃生通道:
- 设太小(如 1 秒):正常业务因短暂锁争抢就被中断,重试风暴风险高
- 设太大(如 60 秒):用户请求挂住一分钟才失败,前端超时、连接池耗尽、雪崩概率上升
- 这个值对已有连接不生效,必须重启或新建连接才加载新配置
真正要治本,得从 SQL 顺序、索引覆盖、事务粒度下手——开关只是掩盖症状,不是解药。











