在当下百花齐放的数据库中,常能看到 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;