概述

Undo Log 是 InnoDB存储引擎实现事务回滚和多版本并发控制(MVCC)的核心机制,记录事务修改前的数据版本,用于保证事务的原子性和一致性。

核心作用

  • 事务回滚:回滚未提交的事务修改
  • MVCC 支持:提供多版本数据供一致性读
  • 崩溃恢复:协助恢复未完成的事务
  • 数据快照:维护数据的多个历史版本

工作机制

存储结构

  • Insert Undo Log:记录 INSERT 操作,回滚时直接删除
  • Update Undo Log:记录 UPDATE/DELETE 操作,回滚时反向操作
  • 组织形式:通过回滚段(Rollback Segment)管理,每个事务对应一个 Undo Log 链

生命周期

  • 事务开始 → 生成 Undo Log
  • 事务修改数据 → 写入 Undo Log
  • 事务提交 → 标记可清理(Purge)
  • Purge 线程 → 清理不再需要的 Undo Log

配置参数

参数默认值说明
innodb_undo_tablespaces2 (8.0+)Undo 表空间数量
innodb_undo_directory./Undo 表空间存储路径
innodb_max_undo_log_size1GB单个 Undo 表空间最大大小
innodb_undo_log_truncateON启用自动截断
innodb_purge_threads4Purge 线程数量

关键参数说明

  1. innodb_undo_tablespaces

    • MySQL 8.0+ 默认启用2个独立的UNDO表空间(undo_001undo_002
    • MySQL 5.7 默认使用共享表空间存储UNDO日志
  2. innodb_undo_directory

    • 默认存储在数据目录下(datadir
    • 可配置为独立存储路径以分散I/O压力
  3. innodb_undo_log_truncate

    • 开启后会自动回收未使用的UNDO空间
    • 需配合 innodb_purge_threads 优化清理效率

配置示例

-- 查看当前UNDO配置
SHOW VARIABLES LIKE '%innodb_undo%';

-- 修改UNDO表空间存储路径(需重启生效)
SET GLOBAL innodb_undo_directory = '/data/undo_logs';

-- 调整最大UNDO表空间大小
SET GLOBAL innodb_max_undo_log_size = 2GB;

注意事项

版本差异:MySQL 5.7 需手动配置 innodb_undo_tablespaces 才能启用独立UNDO表空间
磁盘空间:确保UNDO目录有足够空间,避免事务失败 性能优化:适当增加 innodb_purge_threads
可提升高并发场景的UNDO清理效率

管理操作

查看 Undo 信息:

-- 查看 Undo 表空间
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES 
WHERE SPACE_TYPE = 'Undo';

-- 查看事务使用的 Undo Log
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

手动清理(谨慎使用)

-- 强制触发 Purge 操作(需超级权限)
SET GLOBAL innodb_fast_shutdown = 0;

优缺点分析

优点:

  • 事务保障: 确保 ACID 特性
  • 并发提升: 支持非锁定读
  • 版本管理: 高效处理多版本数据
  • 空间复用: 支持日志重用

缺点:

  • 存储开销: 需要额外存储空间
  • 性能影响: 频繁事务增加 I/O 压力
  • 长事务风险: 未及时清理导致空间膨胀

生产实践

独立存储:配置独立 Undo 表空间

innodb_undo_directory = /ssd_data/undo
innodb_undo_tablespaces = 8

自动截断:启用日志回收

innodb_undo_log_truncate = ON
innodb_max_undo_log_size = 2G

监控告警:

-- 监控 Undo 空间使用
SELECT 
  ROUND(SUM(size)/1024/1024, 2) AS total_undo_mb,
  ROUND(SUM(free)/1024/1024, 2) AS free_undo_mb
FROM INFORMATION_SCHEMA.FILES
WHERE FILE_TYPE = 'UNDO LOG';

长事务处理:

-- 查找长事务
SELECT * FROM information_schema.INNODB_TRX
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;

补充知识

MVCC 实现机制

  • 每个数据行维护 DB_TRX_ID(事务ID)和 DB_ROLL_PTR(回滚指针)
  • Read View 通过 Undo Log构建一致性快照

Purge 流程

  • 确定最旧的活跃事务 ID
  • 清理所有早于该 ID 的 Undo Log
  • 回收空间供新事务使用

版本链示例

Row Data → Undo Log 1 ← Undo Log 2 ← Undo Log 3
          (最新版本)        (历史版本)

故障处理

场景:Undo 空间不足

应急措施:

SET GLOBAL innodb_undo_log_truncate = ON;
SET GLOBAL innodb_max_undo_log_size = 2147483648; -- 2GB

根本解决:

  • 优化事务大小
  • 拆分长事务
  • 增加 Undo 表空间数量

版本差异

特性MySQL 5.7MySQL 8.0
默认表空间共享表空间独立表空间
最小表空间数02
在线调整不支持支持动态修改数量

详细说明

默认表空间
  • MySQL 5.7
    使用共享表空间(ibdata1 文件),所有表数据默认存储在共享表空间中。
  • MySQL 8.0
    默认启用独立表空间(每个表对应 .ibd 文件),提升管理灵活性和性能。
最小表空间数
  • MySQL 5.7
    无最低限制(理论上可为0,但实际需至少包含系统表空间)。
  • MySQL 8.0
    至少需要2个表空间:

    • innodb_system(系统表空间)
    • innodb_undo(UNDO 表空间)
在线调整
  • MySQL 5.7
    表空间数量需停机修改配置文件后重启生效。
  • MySQL 8.0
    支持动态调整表空间数量(如 CREATE TABLESPACEALTER TABLESPACE),无需重启服务。

配置示例(MySQL 8.0)

-- 创建新表空间
CREATE TABLESPACE my_tablespace ADD DATAFILE 'my_tablespace.ibd';

-- 动态修改表空间配置
ALTER TABLESPACE my_tablespace SET AUTOEXTEND_SIZE = 128M;

注意事项

共享表空间问题

  • MySQL 5.7 的共享表空间易导致文件过大且难以收缩。

独立表空间优势

  • MySQL 8.0 的独立表空间支持更细粒度的备份与恢复(如表级导入导出)。

晚上不吃饭
4 声望1 粉丝