一、undo log 的作用
事务回滚
当事务执行过程中出现错误或主动回滚时,innodb 需要将数据恢复到修改前的状态。undo log 记录了数据被修改前的信息,可以根据 undo log 回滚数据。mvcc(多版本并发控制)
为了支持高并发下的读写,innodb 实现了 mvcc。undo log 保存了数据修改前的版本信息,快照读(如 select … where …)可以通过 undo log 读取到历史版本的数据,实现非阻塞读。崩溃恢复
在数据库异常宕机时,undo log 可以帮助恢复未提交事务的数据,保证数据一致性。
二、undo log 的分类
undo log 主要分为两种类型:
insert undo log
记录插入操作(insert),主要用于回滚未提交的插入操作。
只在事务未提交前有效,事务提交后会被立即清理。update undo log
记录更新操作(update、delete),保存被修改行的旧版本。
除了回滚,还用于 mvcc 的快照读,因此即使事务提交,update undo log 还会保留一段时间,直到没有快照读引用它。
三、undo log 的存储
- 在 innodb 中,undo log 并不是单独的文件,而是存储在特殊的表空间中(如
undo tablespace)。 - 早期版本(mysql 5.7 及之前)undo log 存储在系统表空间(ibdata1)中。
- mysql 8.0 开始,支持独立的 undo 表空间,可以更灵活地管理和清理 undo log。
四、undo log 的工作流程
- 当事务对数据进行修改(如 update),innodb 会先将原数据写入 undo log。
- 事务提交前,undo log 会一直保留,用于回滚和快照读。
- 事务提交后,insert undo log 会被立即清理;update undo log 会等到没有快照读引用它时才被清理(称为 purge)。
- undo log 的清理由后台线程(purge)异步进行,避免影响主业务。
五、undo log 与 mvcc 的关系
- innodb 的 mvcc 依赖 undo log 实现。
- 每行记录都有隐藏字段(如 trx_id),记录最后一次修改的事务id。
- 快照读时,innodb 会根据 undo log 回溯到符合条件的版本,实现非阻塞读。
六、undo log 的性能与管理
- undo log 过多会导致表空间膨胀,影响性能。
- 定期清理(purge)很重要,mysql 8.0 支持多线程 purge,提高清理效率。
- 可以通过参数配置 undo 表空间数量、大小等(如
innodb_undo_tablespaces)。
七、相关参数与命令
innodb_undo_tablespaces:设置 undo 表空间数量。innodb_undo_log_truncate:开启自动截断 undo log。show engine innodb status;可以查看当前 undo log 相关信息。
八、常见问题
undo log 占用空间过大怎么办?
- 检查是否有长事务或长时间未提交的快照读。
- 增加 purge 线程数(
innodb_purge_threads)。 - 合理设计业务,避免长事务。
undo log 会影响性能吗?
- undo log 写入是必须的,但一般不会成为性能瓶颈。
- 长时间未清理的 undo log 可能导致空间膨胀,影响性能。
九、undo log 的结构
undo log 并不是简单地记录一行数据的旧值,它实际上是一个链式的数据结构。每个数据行的修改都会生成一个 undo log 记录,这些记录通过链表串联起来,形成所谓的“版本链”。
undo record
每个 undo log 记录包含:- 被修改的行主键
- 修改前的列值
- 事务id(trx_id)
- 操作类型(insert、update、delete)
- 指向上一个版本的指针
版本链(version chain)
每行数据都可以通过 undo log 找到历史版本。快照读时,innodb 会沿着版本链查找满足可见性规则的版本。
十、undo log 的生命周期
生成
事务对数据进行更改时,立即生成 undo log 记录。保留
- 未提交事务:undo log 必须保留,以便回滚。
- 已提交事务:update undo log 还需保留,直到所有快照读都不再需要该版本。
清理(purge)
- 后台 purge 线程会定期清理不再被引用的 undo log。
- 清理时,undo log 会从表空间中物理删除。
十一、undo log 的清理机制(purge)
- 触发时机
- 事务提交后,insert undo log 可立即清理。
- update undo log 只有在所有快照读完成后才能清理。
- 清理过程
- innodb 的 purge 线程会扫描 undo log 链,判断是否有快照读还需要旧版本。
- 如果没有引用,undo log 被物理删除,释放空间。
- 参数调优
innodb_purge_threads:设置 purge 线程数量,提升清理效率。innodb_max_purge_lag:控制 purge 的延迟,防止主业务受影响。
十二、undo log 与 redo log 的区别
| 方面 | undo log | redo log |
|---|---|---|
| 作用 | 回滚、mvcc、快照读 | 崩溃恢复、持久化 |
| 写入时机 | 数据修改前 | 数据修改后 |
| 内容 | 记录数据修改前的旧值 | 记录数据修改后的新值 |
| 事务提交时处理 | 部分立即清理,部分延迟清理 | 需要持久化写盘 |
| 存储位置 | undo 表空间 | redo 日志文件(ib_logfile) |
十三、典型问题分析
长事务导致 undo log 堆积
- 长事务或长时间未提交的快照读会导致 undo log 无法清理,表空间膨胀。
- 解决方法:优化业务逻辑,避免长事务,及时提交。
undo log 影响 ddl 操作
- 大量 undo log 会影响表的 ddl(如 alter table),因为 ddl 需要等待相关 undo log 清理。
- 解决方法:在执行 ddl 前,确保没有长事务和大批量快照读。
undo log 空间回收慢
- undo log 清理依赖 purge 线程,线程数不足会导致清理慢。
- 解决方法:适当增加
innodb_purge_threads,观察show engine innodb status。
十四、undo log 相关源码简析
(如需更深入源码分析可继续追问)
- innodb 的 undo log 相关代码主要在
trx0undo.c、trx0purge.c、row0vers.c等文件。 - 源码实现了 undo log 的生成、链表管理、清理、与 mvcc 的交互。
十五、实践建议
- 避免长事务和大批量未提交的快照读。
- 合理配置 undo 表空间数量和大小。
- 关注 purge 线程运行状况,及时调优相关参数。
- 定期监控 undo log 的空间占用和清理效率。
- 在大数据量操作或 ddl 前,提前处理相关事务,确保 undo log 不会堆积。
总结
undo log 是 innodb 实现事务、回滚、mvcc 的核心机制。合理管理 undo log,有助于提升数据库的稳定性和性能。
到此这篇关于mysql日志undolog的作用的文章就介绍到这了,更多相关mysql日志undolog内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论