mysql 5.7在线收缩UNDO Tablespace

本文介绍 MySQL 5.7 中 Undolog 的动态回收功能,包括相关参数配置、工作原理及示例操作。通过设置 innodb_undo_directory 和 innodb_undo_tablespaces 等参数,实现 Undolog 文件的在线 truncate 和空间回收。

概述

Undo log一直都是事务多版本控制中的核心组件,它具有以下的核心功能

  • 交易的回退:事务在处理过程中遇到异常的时候可以rollback(撤销)所做的全部修改
  • 交易的恢复:数据库实例崩溃时,将磁盘的不正确数据恢复到交易前
  • 读一致性:被查询的记录有事务占用,转向回滚段找事务开始前的数据镜像

虽然Undo log是如此的重要,但在MySQL 5.6(包括5.6)之前Undo tablespace里面的undo数据文件是无法收缩的。也就是说在实例的运行过程中如果遇到有大的事务,会把undo log的文件撑的非常大。进而浪费大量的空间甚至把磁盘打爆。同时也增加了数据库物理备份的时间。在实际的工作中不止一次遇到这类问题。好在MySQL5.7中新增了一个非常有用的功能允许用户在线truncate undo log,进而是undo log文件进行收缩。

5.7 在线truncate undo log

必须使用独立的undo表空间,该功能主要由以下参数控制

  • innodb_undo_directory,指定单独存放undo表空间的目录,默认为.(即datadir),可以设置相对路径或者绝对路径。该参数实例初始化之后虽然不可直接改动,但是可以通过先停库,修改配置文件,然后移动undo表空间文件的方式去修改该参数;
  • innodb_undo_tablespaces,指定单独存放的undo表空间个数,例如如果设置为3,则undo表空间为undo001、undo002、undo003,每个文件初始大小默认为10M。该参数我们推荐设置为大于等于3,原因下文将解释。该参数实例初始化之后不可改动;
  • innodb_undo_logs,指定回滚段的个数(早期版本该参数名字是innodb_rollback_segments),默认128个。每个回滚段可同时支持1024个在线事务。这些回滚段会平均分布到各个undo表空间中。该变量可以动态调整,但是物理上的回滚段不会减少,只是会控制用到的回滚段的个数。
  • innodb_undo_tablespaces>=2。因为truncate undo表空间时,该文件处于inactive状态,如果只有1个undo表空间,那么整个系统在此过程中将处于不可用状态。为了尽可能降低truncate对系统的影响,建议将该参数最少设置为3;
  • innodb_undo_logs>=35(默认128)。因为在MySQL 5.7中,第一个undo log永远在系统表空间中,另外32个undo log分配给了临时表空间,即ibtmp1,至少还有2个undo log才能保证2个undo表空间中每个里面至少有1个undo log;
  • innodb_max_undo_log_size,undo表空间文件超过此值即标记为可收缩,默认1G,可在线修改;
  • innodb_purge_rseg_truncate_frequency,指定purge操作被唤起多少次之后才释放rollback segments。当undo表空间里面的rollback segments被释放时,undo表空间才会被truncate。由此可见,该参数越小,undo表空间被尝试truncate的频率越高。

MySQL 5.7的undo表空间的truncate示例

(1) 首先确保如下参数被正确设置:

  • innodb_max_undo_log_size = 100M
  • innodb_undo_log_truncate = ON
  • innodb_undo_logs = 128
  • innodb_undo_tablespaces = 3
  • innodb_purge_rseg_truncate_frequency = 10

(2) 创建表:


mysql> create table t1( id int primary key auto_increment, name varchar(200));
Query OK, 0 rows affected (0.13 sec)

(3)插入测试数据

mysql> insert into t1(name) values(repeat('a',200));
mysql> insert into t1(name) select name from t1;
mysql> insert into t1(name) select name from t1;
mysql> insert into t1(name) select name from t1;
mysql> insert into t1(name) select name from t1;

这时undo表空间文件大小如下,可以看到有一个undo文件已经超过了100M:


-rw-r----- 1 mysql mysql  13M Feb 25 17:59 undo001
-rw-r----- 1 mysql mysql 128M Feb 25 17:59 undo002
-rw-r----- 1 mysql mysql  64M Feb 25 17:59 undo003

此时,为了,让purge线程运行,可以运行几个delete语句:

mysql> delete from t1 limit 1;
mysql> delete from t1 limit 1;
mysql> delete from t1 limit 1;
mysql> delete from t1 limit 1;

再查看undo文件大小:

-rw-r----- 1 mysql mysql  13M Feb 25 18:05 undo001
-rw-r----- 1 mysql mysql  10M Feb 25 18:05 undo002
-rw-r----- 1 mysql mysql  64M Feb 25 18:05 undo003

可以看到,超过100M的undo文件已经收缩到10M了。

小结

在MySQL 5.7中我们有了一个有效的方法可以在数据库实例运行的过程中动态的回收undo log占用的空间。


转自:http://mysql.taobao.org/monthly/2018/02/09/

<think>嗯,用户这次的问题很明确——想在MySQL中限制undo表空间的大小。从引用内容看,用户已经接触过Oracle的UNDO管理问题(引用1),现在转向MySQL的解决方案,还特意提供了InnoDB引擎相关的技术背景(引用2、3)。用户可能是个DBA或者运维工程师,正在处理实际生产环境中的空间管理问题。 用户引用的材料里其实藏着关键线索:引用2提到InnoDB默认共享表空间,而引用3详细说明了回滚段结构。这暗示限制undo空间需要从两个层面入手——配置独立undo表空间文件并控制其上限(用户提到的.my.cnf配置也验证了这点)。不过用户似乎混淆了Oracle的AUM和MySQL机制,需要明确区分。 核心解决方案应该是innodb_undo_tablespaces配合innodb_max_undo_log_size。但要注意版本差异:MySQL 5.7需要手动分割undo表空间,而8.0的innodb_undo_tablespaces默认值已是2。用户如果环境是8.0,直接设置max参数更高效。另外引用3提到的回滚段计算方式(如16KB页面对应1024个槽位)虽然精确,但实际配置不必深究这个层级。 用户没提MySQL版本,所以回答必须涵盖5.7和8.0的区别。临时方案如truncate虽然有效,但用户显然想要长期配置方案——毕竟ta特意强调“不是临时解决”(引用1里吐槽过Oracle的临时方案)。最后警示purge线程的陷阱很重要,避免用户设错参数导致undo积压。 生成的问题要覆盖延伸场景:比如监控(用户可能没意识到需要持续观察空间使用)和云数据库差异(如果用户在用RDS,直接修改配置文件可能不可行)。 </think>在MySQL中限制Undo表空间大小,主要依靠以下配置参数(适用于InnoDB引擎): ### 核心配置方法 1. **启用独立表空间**(必须步骤) 修改配置文件 `my.cnf`(或 `my.ini`): ```ini [mysqld] innodb_file_per_table = ON # 确保每表独立表空间 innodb_undo_tablespaces = 8 # 创建指定数量的Undo表空间(默认2个) innodb_undo_directory = /path # 可选:指定Undo文件存储路径 ``` 2. **设置Undo表空间上限** ```ini [mysqld] innodb_max_undo_log_size = 1073741824 # 单位:字节(示例=1GB) ``` 3. **自动回收机制** ```ini [mysqld] innodb_undo_log_truncate = ON # 启用自动截断 innodb_purge_rseg_truncate_frequency = 128 # 清理频率(默认128,值越小越频繁) ``` ### 操作步骤 1. **配置参数** 编辑 `my.cnf` 后重启MySQL: ```bash sudo systemctl restart mysql ``` 2. **验证配置** 执行SQL检查: ```sql SHOW VARIABLES LIKE 'innodb_undo%'; -- 确认 innodb_undo_tablespaces, innodb_max_undo_log_size 生效 ``` 3. **手动触发回收(可选)** ```sql ALTER UNDO TABLESPACE tablespace_name SET INACTIVE; -- 标记空间为INACTIVE ALTER UNDO TABLESPACE tablespace_name SET ACTIVE; -- 重新激活触发回收 ``` ### ⚠️ 注意事项 - **MySQL版本要求**: - `innodb_undo_tablespaces`:需 ≥ MySQL 5.7 - `innodb_max_undo_log_size`:需 ≥ MySQL 8.0(5.7需手动管理文件大小)[^3] - **空间监控**: 定期检查 `INFORMATION_SCHEMA.INNODB_TABLESPACES` 中的 `SPACE_SIZE` 字段 - **Purge线程阻塞**: 若Undo清理滞后(如长事务未提交),即使开启截断也可能失败[^3] ### 效果说明 | 参数 | 作用 | 推荐值 | |------|------|--------| | `innodb_max_undo_log_size` | 单个Undo表空间最大容量 | 根据磁盘容量设置(如1-10GB) | | `innodb_undo_log_truncate` | 自动回收空闲空间 | 必须设为 `ON` | | `innodb_undo_tablespaces` | Undo文件数量 | ≥3(避免回收时I/O阻塞) | > 📌 **关键点**:MySQL通过定期将超过 `innodb_max_undo_log_size` 的Undo表空间标记为截断状态,配合Purge线程清理历史版本后释放空间[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值