mysql 8.0死锁检测更及时:默认开启持续追踪等待图,成环即回滚;5.7仅超时后被动扫描。死锁报错增多是问题暴露而非退化,主因是锁序混乱、长事务未提交、间隙锁范围大及监控脚本干扰mdl锁。

死锁检测从“被动扫描”变成“持续追踪”
MySQL 8.0 的 innodb_deadlock_detect 默认开启,后台线程持续维护等待图(wait-for graph),只要锁等待成环就立刻回滚;而 5.7 是被动检测:只有事务等锁超时(默认 50 秒)才触发一次全图遍历。这不是“更快”,是“更及时”——热点行冲突时,一个事务不会卡住整个 worker 线程池。
为什么升级后死锁报错变多,不是性能退化而是问题暴露
常见错误现象:Deadlock found when trying to get lock 在日志里密集出现,但业务没明显卡顿。这不是 8.0 检测变差,而是原来被静默忽略的隐性死锁现在全被揪出来了。
- 用
SHOW ENGINE INNODB STATUS\G查最近一次死锁,重点看TRANSACTIONS部分的HELD LOCKS和WAITING FOR THIS LOCK TO BE GRANTED - 若事务 A 持有
table_a行锁却等待table_b,而事务 B 持有table_b却等待table_a,就是应用层锁序混乱,得改代码,不是调参数能解决的 - 检查是否有
SELECT ... FOR UPDATE后长期不COMMIT或ROLLBACK的会话(查information_schema.INNODB_TRX中trx_started时间过早的记录)
容易被忽略的底层变化:行锁唤醒策略更公平
8.0 改了行锁唤醒逻辑:不再优先唤醒最早等待的事务,而是按资源等待的“公平性”调度。这会让过去靠“抢跑”侥幸成功的长事务,在 8.0 下更容易被卡住、超时,进而触发连锁重试或阻塞——表面是死锁变多,实则是旧有“饥饿”逻辑在新机制下失效了。
批量更新中若用了 IN (1,2,3,...,1000) 且没走索引,间隙锁范围过大,多个事务同时扫描同一区间,极易形成循环等待;这类语句在 8.0 下更危险,不是因为锁本身变重,而是等待队列不再容忍无序竞争。
监控脚本也可能间接推高死锁感知频率
sys.innodb_lock_waits 在 8.0 中底层依赖 performance_schema.data_locks,读取时会申请 MDL 锁。如果此时恰有 DDL 正在执行(比如加字段),监控脚本就会卡在 Waiting for table metadata lock,拖慢连接池响应,锁等待时间拉长,死锁概率自然上升——这种“伪死锁上升”和锁机制无关,但排查时最容易误判。
真正影响死锁检测效率的,从来不是 CPU 花多少时间扫图,而是图是否实时、等待是否被公平调度、以及监控是否干扰了正常锁流。8.0 把这些隐性延迟拿掉了,所以看起来“更准”,也“更刺眼”。











