MySQL 8.0 锁等待严重如何排查事务锁占用情况?

文章导读
MySQL 8.0 排查锁等待严重问题,最推荐直接查询 performance_schema.data_lock_waits 视图定位阻塞源,适用在线业务紧急止血场景,风险在于误杀关键事务可能导致数据回滚。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

MySQL 8.0 排查锁等待严重问题,最推荐直接查询 performance_schema.data_lock_waits 视图定位阻塞源,适用在线业务紧急止血场景,风险在于误杀关键事务可能导致数据回滚。

先说结论:优先通过 performance_schema 定位持有锁的事务 ID,确认阻塞 SQL 后再决定是否终止事务

  • 先定位:查询 data_lock_waits 找到 blocking_engine_transaction_id
  • 先处理:关联 innodb_trx 查看长事务来源,评估是否 Kill
  • 再验证:观察 Innodb_row_lock_waits 状态值是否下降

命令速用版

以下 SQL 可直接在 MySQL 8.0 实例执行,用于快速找出当前正在阻塞其他事务的会话和 SQL 语句。

SELECT w.*, t.trx_query, t.trx_mysql_thread_id
FROM performance_schema.data_lock_waits w
JOIN information_schema.innodb_trx t
ON w.blocking_engine_transaction_id = t.trx_id;

若需查看等待锁的具体会话信息,可关联 processlist 表:

SELECT w.*, p.user, p.host, p.command
FROM performance_schema.data_lock_waits w
JOIN information_schema.processlist p
ON w.blocking_engine_thread_id = p.id;

为什么会这样

锁等待严重通常是因为某个事务持有锁时间过长,导致后续请求排队。

InnoDB 引擎使用行锁控制并发,当事务 A 修改了某行数据未提交,事务 B 再修改同一行数据时就会进入等待状态。MySQL 8.0 引入了 performance_schema.data_locks 和 performance_schema.data_lock_waits 表,相比旧版本的 SHOW ENGINE INNODB STATUS,能更结构化地展示锁等待关系。公开资料中没有看到可靠的量化数据说明新视图带来的性能开销,但在排查效率上官方文档明确推荐用于锁诊断。

分步处理

按以下步骤操作,每一步完成后需确认当前状态再进入下一步。

步骤 1:确认锁等待现状

查询全局状态,确认是否存在行锁等待:

MySQL 8.0 锁等待严重如何排查事务锁占用情况?
SHOW STATUS LIKE 'Innodb_row_lock_waits';

如果值持续增加,说明存在锁竞争。

步骤 2:定位阻塞源

执行“命令速用版”中的查询语句,找到 blocking_engine_transaction_id 对应的 trx_query。

适用场景:业务出现超时报错 Error 1205 (Lock wait timeout exceeded)。

风险边界:不要直接 Kill 系统后台事务,需确认 trx_query 是否为业务 SQL。

步骤 3:处理阻塞事务

若确认阻塞事务为异常长事务,使用以下命令终止会话:

KILL [trx_mysql_thread_id];

MySQL 8.0 锁等待严重如何排查事务锁占用情况?

操作动作:替换 ID 为查询到的线程 ID。

验证结果:被 Kill 的事务回滚,锁释放,等待队列减少。

步骤 4:优化根源

检查阻塞 SQL 是否缺少索引导致锁范围扩大,或事务逻辑是否包含非数据库操作(如 HTTP 请求)。

怎么验证是否生效

执行以下命令观察锁等待计数是否停止增长:

SHOW STATUS LIKE 'Innodb_row_lock_waits';
SHOW STATUS LIKE 'Innodb_row_lock_time_avg';

同时观察业务侧报错日志,Error 1205 频率应明显降低。

若使用监控面板,检查数据库活跃会话数(Active Sessions)是否回落。

常见坑

1. 元数据锁(MDL)混淆:performance_schema.data_lock_waits 主要展示行锁,若遇到 DDL 阻塞,需查询 performance_schema.metadata_locks 表。

MySQL 8.0 锁等待严重如何排查事务锁占用情况?

2. 间隙锁(Gap Lock):某些查询看似不冲突,但因间隙锁导致范围阻塞,需检查 trx_query 是否包含范围查询且未走唯一索引。

3. Kill 错事务:终止事务会导致回滚,大事务回滚可能耗时更长,加剧阻塞,操作前需评估事务大小。

常见问题

锁等待和死锁有什么区别?

锁等待是事务排队等待锁释放,死锁是两个事务互相等待对方释放锁。

锁等待通常由长事务引起,死锁通常由并发更新顺序不一致引起,MySQL 会自动检测死锁并回滚其中一个。

innodb_lock_wait_timeout 设置多少合适?

默认值为 50 秒,具体数值需根据业务容忍度调整。

调小该参数可以让失败更快返回,但不能解决锁竞争根源,仅适用于快速失败场景。

为什么查不到 data_lock_waits 数据?

可能当前没有正在发生的锁等待,或者 performance_schema 未开启。

需确认变量 performance_schema 状态为 ON,且当前时刻确实存在未完成的锁请求。

参考来源

  • MySQL Official Documentation, "InnoDB Locking Reads", https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html
  • MySQL Official Documentation, "Performance Schema Lock Tables", https://dev.mysql.com/doc/refman/8.0/en/performance-schema-lock-tables.html
  • MySQL Official Documentation, "The INFORMATION_SCHEMA INNODB_TRX Table", https://dev.mysql.com/doc/refman/8.0/en/innodb-trx-table.html