数据库 UNDO 日志详解


在当下百花齐放的数据库中,常能看到 bin logredo logundo log 等名词,其各自扮演着重要角色。

而今天则让我们聚焦于 undo log,当开启数据事务后,数据库会将变更前的内容记录至 undo 文件中,当触发回滚等操作时,则可读取 undo 日志文件回滚至变更前原始记录,可谓是数据库事务的基石。

倘若 undo log 空间过慢而未及时清理,则可能导致系统服务瘫痪等风险,下面就让我们一同深入了解 MySQLOracleundo log 其相应的机制。

一、MySQL

1. 服务配置

正如上述所提到,undo log 用于处理数据库中的事务操作,可通过下述命令查询 undo 相关配置:

show VARIABLES like '%undo%';

MySQLundo 日志涉及指标如图所示:

(1) innodb_undo_tablespaces

参数为 undo 表空间数量,表示 undo 存储的文件数,如值为 2 数据将分为 undo_001、undo_002 存储。

其最大值为 128,在 5.7 中默认为 0 表示不独立设置 tablespace,即数据保存于系统表空间 ibdata1 中。在 8.0 之后默认值为 2,注意 innodb_undo_tablespaces 在服务启动之后便不可再进行调整。

(2) innodb_max_undo_log_size

单个 undo 表空间文件的最大值,默认值为 1024MB

(3) innodb_undo_logs

表示 InnoDB 可用的回滚段 (Rollback Segments),存储了事务的修改前镜像,此参数在 MySQL 8.0 后已废弃。

(4) innodb_undo_log_truncate

参数配置是否允许回收,如果为 off 表示不允许 truncate 则文件会持续增长直到磁盘满。

当值设为 on 开启回收时,若 undo 文件大小超过 innodb_max_undo_log_size 且表空间状态为 inactive 时则会重置文件至 10MB

可通过下述方式手动释放空间,但需注意当前服务无进行中事务进程。

-- 将 undo 表空间设为非活跃
ALTER UNDO TABLESPACE undo_001 SET INACTIVE;

-- 截断文件
ALTER UNDO TABLESPACE undo_001 TRUNCATE;

-- 重新启用
ALTER UNDO TABLESPACE undo_001 SET ACTIVE;

2. 占比统计

通过下述语句可查询当前使用中的 undo 槽,即一个运行时监控指标。

每个活跃事务都需要一个 undo(Segments) 来存储自己的 undo 记录,而每个 undo 段会对应一个 undo(Slot)

SELECT
    NAME,
    COUNT,
    TYPE
FROM
    information_schema.innodb_metrics
WHERE
    NAME LIKE 'trx_undo%';

这边我们可以关注下述表中两个属性:

属性 作用
trx_undo_slots_used 当前正在使用的 slot 数量。
trx_undo_slots_cached 已分配但空闲的 slot。

二、Oracle

1. 服务配置

Oracle 中同样通过 undo 日志实现事务的管理,通过下述语句查询 undo 配置信息:

SHOW PARAMETER undo;

Oracleundo 日志配置涉及下述三项指标:

属性 描述
undo_tablespace 当前实例使用的 UNDO 表空间。
undo_management 一般为 AUTO,即表示自动管理。
undo_retention 指定事务提交后 UNDO 数据至少保留的时间(秒),默认 900 秒。

上述查询语句需通过控制台查询,若普通查询可通过视图表实现,查询结果一致。

SELECT
    name,
    value
FROM
    v$parameter
WHERE
    name LIKE 'undo%';

2. 服务模式

Oracle 中的 undo 日志文件同样涉及清除操作,通过不同的保证模式实现控制。

通过下述语句查询不同命名空间的保证模式:

SELECT
    tablespace_name,
    retention
FROM
    dba_tablespaces
WHERE
    tablespace_name LIKE 'UNDO%';
(1) NOGUARANTEE

默认值,当空间不足时即使没到 undo_retention 时间,也会覆盖旧的 undo 数据。

(2) GUARANTEE

严格保证 undo_retention,即在保留时间内 undo 数据不会被覆盖,可能导致 DML 报错。

可通过下述命令修改 undo 日志保证模式:

ALTER DATABASE UNDO TABLESPACE undotbs1 RETENTION GUARANTEE;

ALTER DATABASE UNDO TABLESPACE undotbs1 RETENTION NOGUARANTEE;

3. 文件信息

通过下述语句则可查询当前 undo 日志每个命名空间的文件使用情况。

SELECT
    tablespace_name,
    file_name,
    bytes / 1024 / 1024 AS size_mb,
    autoextensible,
    maxbytes / 1024 / 1024 AS max_size_mb
FROM
    dba_data_files
WHERE
    tablespace_name = 'UNDOTBS1';
4. 进程状态

同样的,以 undo_retention 过期时间为依据,每个 undo 日志命名空间下的进程也存在状态区分。

通过下述语句便可统计查询各命名空间下不同状态文件的占用情况。

SELECT
    tablespace_name,
    status,
    SUM (bytes) / 1024 / 1024 "Bytes(M)"
FROM
    dba_undo_extents
GROUP BY
    tablespace_name,
    status;
(1) status = ACTIVE

表示当前有事务正在使用该 extent,不能覆盖。

(2) status = UNEXPIRED

表示其已经没有事务在使用中,但仍在 undo_retention 保留期内,理论上不会覆盖除非空间不足(若处于 NOGUARANTEE 模式)。

(3) status = EXPIRED

表示已经过了保留期,可以被新的事务覆盖使用;

下述语句则不区分 status 状态,统计当前 undo 使用信息:

SELECT
    a.tablespace_name,
    ROUND(a.bytes / 1024 / 1024, 2) AS total_mb,
    ROUND((a.bytes - b.bytes_used)/ 1024 / 1024, 2) AS used_mb,
    ROUND(b.bytes_used / 1024 / 1024, 2) AS free_mb,
    ROUND(((a.bytes - b.bytes_used)/ a.bytes) * 100, 2) AS used_percent
FROM
    (
        SELECT
            tablespace_name,
            SUM(bytes) bytes
        FROM
            dba_data_files
        WHERE
            tablespace_name LIKE 'UNDO%'
        GROUP BY
            tablespace_name
    ) a,
    (
        SELECT
            tablespace_name,
            SUM(bytes) bytes_used
        FROM
            dba_free_space
        WHERE
            tablespace_name LIKE 'UNDO%'
        GROUP BY
            tablespace_name
    ) b
WHERE
    a.tablespace_name = b.tablespace_name;

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录