mysql死锁如何排查_mysql锁日志分析方法

来源:这里教程网 时间:2026-02-28 20:52:56 作者:

直接看
SHOW ENGINE INNODB STATUS
最新死锁日志

MySQL 默认只保留**最近一次**死锁的完整现场,不存历史记录。所以出问题后第一反应就是立刻执行:

SHOW ENGINE INNODB STATUS\G
然后在输出里搜
LATEST DETECTED DEADLOCK
—— 这段内容会覆盖之前所有死锁日志,稍慢一步就丢了。

常见错误是等业务报错后再去查,结果发现日志已更新为下一次死锁(甚至没再发生),导致“明明出了错却看不到现场”。建议在监控告警触发时,立刻人工或脚本拉取该命令结果。

仅对当前连接生效,无需权限,但需有
PROCESS
权限(RDS 通常默认开放)
输出中事务 ID(如
TRANSACTION 12345
)、持有锁(
HOLDS THE LOCK(S)
)、等待锁(
WAITING FOR THIS LOCK
)三块必须对照着看
注意末尾那句被回滚的 SQL,它不是“罪魁祸首”,而是压垮骆驼的最后一根稻草——真正的问题藏在两个事务访问资源的**顺序差异**里

让所有死锁都落盘:开启
innodb_print_all_deadlocks

靠手动抓

SHOW ENGINE
太被动,尤其线上偶发、低频死锁根本来不及响应。必须改配置,把每次死锁都写进错误日志:

my.cnf
[mysqld]
段加上:
innodb_print_all_deadlocks = ON<br>log_error = /var/log/mysql/error.log

重启 MySQL 生效(RDS 可通过参数模板修改,无需重启) 日志会追加到
log_error
指定路径,用
grep -A 20 -B 5 "Deadlock" /var/log/mysql/error.log
快速提取
⚠️ 别忽略磁盘空间:高频死锁时日志增长快,建议配合 logrotate 或云服务的日志轮转策略

从日志定位“谁在锁谁”:看 space id + page no + index

死锁日志里这类行最烧脑也最关键:

RECORD LOCKS space id 88 page no 7 index `idx_account`
它不告诉你哪条数据,但给出了精确物理位置:

space id
对应表空间(一般等于
INFORMATION_SCHEMA.INNODB_TABLES.TABLE_ID
page no
是页号,结合
index
名可反查冲突行所在索引的范围
例如两个事务分别卡在
idx_name
PRIMARY
上,基本能断定是“先更新非主键索引,再删主键行” vs “先删主键行,再更新非主键索引”这种经典反序操作

真要精确定位某一行?用

SELECT * FROM table WHERE id = ?
查主键值不靠谱——因为锁可能落在间隙(gap lock)上。更稳的方式是用
SELECT * FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE WHERE SPACE = 88 AND PAGE_NUMBER = 7
(需开启
innodb_buffer_page
监控,生产慎用)。

云数据库别只盯命令:善用控制台“死锁分析”页签

华为云 RDS、GaussDB、TaurusDB 等托管服务都内置了可视化死锁分析能力,比手撕日志快得多:

进控制台 → 找到目标实例 → “锁&事务” → “死锁分析”页签 “最近死锁分析”展示最后一次死锁的图形化等待链(事务 A → B → C → A) “全量死锁分析”需手动开启开关,支持查最近 7 天全部死锁(注意:未开启前的历史数据不可恢复) 关键字段如
happen_time
Object
(死锁内容 JSON)、
SQL
原始语句都直接可点开

容易被忽略的是:这些页面显示的 SQL 是“被回滚的那条”,而真正引发竞争的前置操作(比如一个没加

FOR UPDATE
SELECT
引发了隐式锁升级)并不会出现在这里——它只记录最终碰撞点,不记录全过程。

相关推荐