首页/数据/数据库速查/锁等待与死锁的 SQL 级分析
SQL 语法52 条

锁等待与死锁的 SQL 级分析

用 sys.innodb_lock_waits 找到阻塞链,用 performance_schema.data_locks 看锁位点,最后用固定顺序 + 短事务根治。

数据库速查数据更新于 2026-10-13

锁等待与死锁的 SQL 级分析是什么

InnoDB 的锁问题分两种:锁等待是有人先拿了锁,别人排队,超时报 1205;死锁是双方互相等对方持有的锁,InnoDB 主动检测并回滚代价较小的一方,报 1213。定位靠三样东西:sys.innodb_lock_waits 给出的阻塞链、performance_schema.data_locks 的持锁与等锁明细、以及 information_schema.INNODB_TRX 里的事务时长与语句。

基本信息

适用版本MySQL 5.7 / 8.0(8.0 用 data_locks / data_lock_waits 视图)
核心视图sys.innodb_lock_waits、performance_schema.data_locks、INNODB_TRX
超时参数innodb_lock_wait_timeout(默认 50 秒)
错误码1205 锁等待超时、1213 死锁被回滚
根治方向统一加锁顺序、缩短事务、命中索引减少锁范围

典型使用场景

  • 线上频繁报 1205:确认到底是哪条 SQL 在阻塞,是不是长事务没提交
  • 应用报 1213 死锁:取 InnoDB 状态里的死锁日志,还原两个事务的加锁顺序
  • 批量任务跑不动:自身分批提交的事务与其他业务互相等待
  • 结构变更前的评估:DDL 需要等所有长事务结束,提前清理阻塞
  • 压测与容量评估:观察高并发下的锁等待峰值是否可接受

阻塞链定位

阻塞链定位
-- 谁在等、被谁挡、等了多久
SELECT waiting_pid, waiting_query, blocking_pid, blocking_query, wait_age
FROM sys.innodb_lock_waits\G

-- 当前所有锁明细:看锁类型、模式、涉及的表与索引
SELECT * FROM performance_schema.data_locks LIMIT 20;
SELECT * FROM performance_schema.data_lock_waits LIMIT 20;

-- 未提交事务清单:重点看 trx_started 与 trx_rows_locked
SELECT trx_id, trx_state, trx_started, trx_rows_locked, trx_query
FROM information_schema.INNODB_TRX ORDER BY trx_started;

处置与根治

处置与根治
-- 先看阻塞方的完整语句与开启时间,再决定处置方式
SELECT id, user, time, state, info FROM information_schema.PROCESSLIST WHERE time > 60;

-- 确认是失控的长事务再终止(会回滚该事务的全部修改)
KILL 12345;

-- 临时放宽等待时间,给批处理留出空间(仅限特定场景)
SET SESSION innodb_lock_wait_timeout = 120;

-- 查看最近一次死锁的详细记录
SHOW ENGINE INNODB STATUS\G     # 只看 LATEST DETECTED DEADLOCK 段

关键字段读法

字段含义怎么用
waiting_pid正在等待锁的会话通常是要救的对象,可能是业务关键请求
blocking_pid持锁不让的会话看它的 trx_started 与 SQL,找根因
wait_age已等待时长增长到接近超时阈值就该主动干预
lock_type / lock_mode锁层次与模式(X、S、GAP 等)判断是行锁、间隙锁还是表级元数据锁
trx_rows_locked事务已锁行数数值大说明扫描范围过宽,多半缺索引
死锁不必恐慌:InnoDB 会自动检测并回滚代价小的一方,应用侧只要对 1213 做有界重试即可;真正必须立刻干预的信号是锁等待超时长时间积压,以及元数据锁导致的整体阻塞。
KILL 会话会回滚其未提交的整个事务,涉及大事务时可能引发长时间回滚并放大 IO;执行前先确认该事务的写入量与应用影响面,能等提交就优先等。

易错点

  • 只看 waiting 语句就去 KILL:应该先看 blocking 方的开启时间与 SQL,否则杀了等待者下一刻还会再堵
  • 事务里混入用户交互或远程调用:事务持有时间从毫秒变成秒级,锁等待成倍放大
  • 同一业务在不同代码路径中按不同顺序更新多张表:并发下死锁几乎必然出现,需在规范里固定顺序
  • 条件下推不到索引:更新一张大表实际锁住大量行,间隙锁进一步扩大冲突范围
  • 对死锁不做重试:偶发死锁直接把用户请求打成报错,可用有界退避重试吸收

数据来源与参考

  • MySQL 8.0 Reference Manual: The sys Schema - innodb_lock_waits

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌