INNODB_STATUS 的 TRANSACTIONS 部分是锁等待分析第一现场,重点关注 waiting for lock to be granted、Trx has been waiting 秒数、lock_mode 类型及 purge 滞后;performance_schema 提供实时锁链追踪;pt-deadlock-logger 捕获死锁模式;slow_log 不记录锁等待SQL,需结合 events_statements_history_long 与 data_lock_waits 分析。

怎么看 innodb_status 里的锁等待信息
MySQL 的 SHOW ENGINE INNODB STATUS 输出里,TRANSACTIONS 部分是锁等待分析的第一现场。它不实时刷新(默认每 15 秒更新一次),但胜在无需额外配置,适合快速抓取瞬时快照。
重点盯住两块内容:---TRANSACTION xxx, ACTIVE xxx sec 下的 waiting for lock to be granted 行,和紧随其后的 LOCK WAIT 块;以及被阻塞事务下面那个 Trx has been waiting ... sec 的计时——超过 5 秒就该怀疑了。
- 如果看到
lock_mode X locks rec but not gap waiting,说明是行锁等待,大概率是 UPDATE/DELETE 没走索引或走了范围扫描 -
lock_mode S locks rec but not gap waiting多出现在 SELECT ... FOR UPDATE / SHARE MODE 场景,注意检查是否误用了共享锁 - 输出中出现大量
Trx id counter和Purge done滞后,可能意味着 purge 线程卡住,间接拖慢锁释放
用 performance_schema 监控实时锁等待链
performance_schema 是比 INNODB_STATUS 更细、更可控的锁分析入口,前提是 MySQL ≥ 5.6 且已启用相关 consumers 和 instruments。
关键表有三个:data_locks(当前持有的锁)、data_lock_waits(谁在等谁)、events_statements_current(对应 SQL)。
- 必须先确认开启:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_current';,再打开wait/lock/innoDB/table和wait/lock/innoDB/record - 查锁等待链:连接
data_lock_waits和events_statements_current,用LOCK_TRX_ID和BLOCKING_TRX_ID关联,就能定位到阻塞者和被阻塞者的完整 SQL - 注意
data_locks中的INDEX_NAME字段——如果显示GEN_CLUST_INDEX,说明没走二级索引,正在扫聚簇索引,锁范围大、易冲突
pt-deadlock-logger 抓取死锁并反查原始 SQL
pt-deadlock-logger 是 Percona Toolkit 里最实用的锁分析工具,它能持续监听 error log 中的 Deadlock found when trying to get lock 记录,并自动提取事务 ID、SQL、时间戳、锁类型等字段存入表中。
它不解决锁等待,但死锁日志里藏着最典型的“锁竞争模式”:比如两个事务以不同顺序访问相同几行,或者一个事务持 S 锁又申请 X 锁。
- 运行前确保 MySQL error log 开启了
log_error_verbosity = 3(MySQL 8.0+),否则死锁详情会被截断 - 推荐把日志存进表里:
pt-deadlock-logger --user=u --password=p --host=h --dest D=test,t=deadlocks,后续可按server、ts、query聚合分析高频冲突 SQL - 注意日志里
*** (1) TRANSACTION:和*** (2) TRANSACTION:下面的mysql tables in use和locked tables行——它们暴露了事务涉及的表和锁粒度
为什么 slow_log 里查不到锁等待的 SQL
锁等待本身不会让 SQL 变慢到触发 long_query_time,所以即使一条 UPDATE 卡了 30 秒在等锁,只要执行阶段耗时短,就不会进 slow log。这是新手最容易误判的一点。
真正要查的是“执行完成但耗时异常高”的 SQL——它们往往就是锁等待的受害者,而非发起者。
- 开
log_slow_admin_statements = ON和log_queries_not_using_indexes = ON,辅助判断是否因缺失索引导致锁范围过大 - 结合
performance_schema.events_statements_history_long查最近执行过的语句,过滤TIMER_WAIT异常高的记录,再关联data_lock_waits看当时是否在等锁 - 监控系统里如果只看 P95 响应时间突增,但 QPS 没明显变化,优先排查锁等待,而不是盲目优化 SQL 执行计划
锁等待不是单条 SQL 的问题,而是多事务协作时序的产物。哪怕所有 SQL 都加了索引、都走主键,只要访问顺序不一致,就可能形成环路。定位时别只盯着“慢”的那条,得把整个事务生命周期串起来看。


















