Lv log

Mysql 日志分析结果

922 字
3 分钟阅读

我先读取这个 CSV 文件,了解日志内容的结构和数据。
我已经读取了日志文件,这是一个 MySQL InnoDB 死锁(Deadlock)日志,问题非常明确。下面我给你一份完整分析。


🔍 日志分析结果

一、问题本质:InnoDB 死锁(Deadlock)

日志中反复出现:

1
2
InnoDB: Transactions deadlock detected, dumping detailed information.
InnoDB: WE ROLL BACK TRANSACTION (1)

这是 MySQL 检测到死锁后,主动回滚其中一个事务以解除死锁的标准行为。


二、涉事 SQL(所有死锁的共同点)

1
2
3
4
DELETE FROM `times_original`
WHERE `account_id` = ?
AND `date` = ?
AND `fm` = ?

涉及的时间段:2026-06-19 ~ 2026-07-01fm 值为 94


三、死锁根因:两个索引交叉等待

这是典型的 索引锁交叉死锁,两个事务各自持有对方需要的锁:

事务 已持有锁(HOLDS) 等待锁(WAITING FOR)
Tx 1 index date 的 X 锁 index account_id 的 X 锁
Tx 2 index account_id 的 X 锁 index date 的 X 锁

形成闭环,死锁发生。


四、为什么会发生这种交叉锁?

核心原因:DELETE 语句没有最优索引,导致分别走不同索引,锁的顺序不一致。

  1. 并发执行两条 DELETE,分别用不同的 account_id
  2. 事务 A 先锁 account_id 索引记录,再去锁 date 索引
  3. 事务 B 先锁 date 索引记录,再去锁 account_id 索引
  4. 互相等待 → 死锁

此外,日志中还有以下佐证:

  • LOCK WAIT + 大量 lock struct(有的事务积累了 1500+ 个锁结构),说明锁持有时间长、范围广
  • fetching rows 状态说明 DELETE 在扫描大量行
  • Got an error reading communication packets:客户端因等待超时而断开,说明锁等待时间很长

五、死锁发生时间线(部分)

时间 account_id 回滚事务
20:09:40 5787 Tx (1)
19:22:36 6734 Tx (1)
17:53:28 6655 Tx (1)
17:14:30 5874 Tx (2)
17:10:24 6626 Tx (2)
16:29:24 5872 Tx (2)
15:56:20 6701 Tx (1)
21:27:26(昨天) 7949 Tx (1)

死锁非常频繁,几乎每小时都在发生。


六、解决方案(按优先级)

✅ 方案 1(最重要):建复合索引

1
2
CREATE INDEX idx_times_original_account_date_fm
ON `times_original` (`account_id`, `date`, `fm`);

效果:DELETE 只走一个索引,锁顺序一致,从根本上消除交叉锁死锁。

⚠️ 建索引前请确认现有索引:

1
SHOW INDEX FROM `times_original`;

如果已有 (account_id, date, fm) 的开头前缀索引,则无需重复创建。


✅ 方案 2:降低并发度

多个应用线程同时执行同表 DELETE 是死锁的催化剂。可以:

  • 对同一个 account_id 的删除操作加分布式锁(如 Redis 锁),保证串行化
  • 或在应用层用队列控制并发

✅ 方案 3:缩小事务范围

日志中看到部分事务持有 1000+ 个行锁LOCK WAIT 1484 lock struct(s)),说明单次 DELETE 影响行数过多。

改为分批删除

1
2
3
4
5
DELETE FROM `times_original`
WHERE `account_id` = ?
AND `date` = ?
AND `fm` = ?
LIMIT 1000;

循环执行直到删除完毕,减少单次事务锁持有量。


✅ 方案 4:调整隔离级别(辅助手段)

如果业务允许,考虑将事务隔离级别从 REPEATABLE READ 改为 READ COMMITTED

1
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

这可以减少 Gap Lock 的范围,降低死锁概率(但不能根治)。


七、总结

问题 原因 解决
死锁频繁 无最优复合索引,两索引交叉加锁 (account_id, date, fm) 复合索引
锁等待时间长 单次 DELETE 影响行数过多 分批 DELETE + LIMIT
客户端超时断开 锁等待超时 降低并发 + 优化索引

首要任务:确认 times_original 表现在有哪些索引,然后创建复合索引。如果你能把 SHOW CREATE TABLE times_original; 的结果发我,我可以帮你确认最准确的索引优化方案。

© 2026 Lv log

Elegant theme by Shiro · Made by Acris with ❤️