查锁冲突需先排除网络、i/o或sql慢等非锁因素;重点分析阻塞链而非静态锁快照,mysql 8.0推荐用performance_schema.data_lock_waits联合innodb_trx和processlist定位具体等待事务及行锁数据。

查锁冲突得先确认是不是真的被锁住了
很多情况下看到查询卡住,第一反应是“有锁”,但实际可能是网络延迟、磁盘 I/O 堵塞,或者 SQL 本身执行太慢。直接查 sys.innodb_lock_waits 可能返回空——不是没锁,而是当前没有活跃的**等待态锁冲突**(即一个事务在等另一个事务释放锁)。真正要盯的是正在运行的阻塞链,而不是“谁锁了谁”的静态快照。
实操建议:
- 先用
SHOW ENGINE INNODB STATUS\G看最近的死锁或锁等待摘要,它会显示最后一次死锁详情和当前锁队列头部事务 - 再查
information_schema.INNODB_TRX,看有没有长时间运行(TRX_STARTED很早)且状态为LOCK WAIT的事务 - 配合
information_schema.INNODB_LOCKS(MySQL 5.7)或performance_schema.data_locks(MySQL 8.0+)定位具体锁对象,注意后者默认关闭,需开启:SET GLOBAL performance_schema = ON;
MySQL 8.0 怎么用 sys.schema_table_lock_waits 查表级锁
sys.schema_table_lock_waits 是个视图,只暴露表级元数据锁(MDL),比如 ALTER TABLE 被 SELECT 阻塞时的场景。它不反映行锁或间隙锁,别指望靠它查到 UPDATE 之间的行锁冲突。
常见错误现象:执行 SELECT * FROM sys.schema_table_lock_waits; 返回空,但业务明显卡住——大概率是行锁问题,不是 MDL。
实操建议:
- 确认 MySQL 版本是否 ≥ 8.0(
SELECT VERSION();),该视图在 5.7 不可用 - 确保
performance_schema已启用,且events_statements_history_long和data_locks消费器已打开(否则视图无数据) - 字段
blocking_pid和waiting_pid对应的是 processlist id,可联查information_schema.PROCESSLIST获取 SQL 原文 - 注意
object_schema/object_name是被锁的表,但不表示锁类型;真正锁粒度要看lock_type(如EXCLUSIVE、SHARED_READ)
怎么关联查出谁在等谁、等的是哪一行
核心思路:把事务、锁、SQL 三者串起来。MySQL 8.0 后最可靠路径是 performance_schema.data_locks + performance_schema.data_lock_waits + information_schema.INNODB_TRX。
容易踩的坑:直接 JOIN 这几张表容易漏掉“持有锁但未等待”的事务(比如长事务没被等,但它锁着数据不让别人改);另外 data_lock_waits 只记录当前等待关系,一旦锁释放就消失。
实操建议:
- 先查
SELECT * FROM performance_schema.data_lock_waits;找出BLOCKING_TRX_ID和WAITING_TRX_ID - 用这两个 ID 去
INNODB_TRX查对应事务的TRX_MYSQL_THREAD_ID,再联PROCESSLIST拿 SQL - 用
BLOCKING_TRX_ID查data_locks,看LOCK_DATA字段——如果是行锁,这里会显示主键值(如123);如果是间隙锁,可能显示supremum pseudo-record或范围(如100, 200) - 注意
LOCK_MODE:X,REC_NOT_GAP是行锁,X,GAP是间隙锁,X,INSERT_INTENTION是插入意向锁——它们都可能互斥
为什么开了 performance_schema 还查不到锁信息
不是开了就自动收集所有锁事件。performance_schema 默认只开启部分消费者(consumer),而锁相关数据依赖 events_transactions_current、data_locks、data_lock_waits 这几个关键项,它们默认是关的。
性能影响确实存在:全量开启锁监控会使高并发写入场景下性能下降 5–15%,尤其在小事务频繁提交时。所以生产环境一般只在排查期间临时打开。
实操建议:
- 检查是否启用:
SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE 'global_instrumentation' OR NAME LIKE '%data%'; - 临时开启(重启后失效):
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME IN ('global_instrumentation', 'thread_instrumentation', 'events_transactions_current', 'data_locks', 'data_lock_waits'); - 别忘了开 instruments:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'transaction%'; - 如果只想要锁摘要,用
sys.innodb_lock_waits更轻量,但它底层也依赖performance_schema的开关状态
锁分析最麻烦的从来不是查不到,而是查到一堆锁却分不清哪个是根因——比如一个长事务持有着多把锁,而十几个短事务在不同位置排队等它,这时候得从 TRX_STARTED 时间和 TRX_QUERY 内容反推业务逻辑,而不是盯着锁本身。











