数据库 UNDO 日志详解


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

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

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

一、MySQL

1. 服务配置

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

show VARIABLES like '%undo%';

MySQL 中 undo 日志涉及指标如图所示:

(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;

Oracle 中 undo 日志配置涉及下述三项指标:

属性 描述
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 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
赏
  目录