Oracle UNDO表空间管理维护总结

Oracle UNDO表空间管理维护总结


一、UNDO概述

1.1 什么是UNDO

UNDO(撤销)数据是Oracle数据库中用于回滚或撤销对数据库所做更改的信息。这些信息由事务操作记录组成,主要在事务提交之前产生,统称为UNDO数据。

UNDO表空间是Oracle数据库中用于存储数据修改前镜像(Before Image) 的专用表空间。每次执行增删改UPDATEDELETEINSERT操作时,Oracle都会在修改数据块之前,先将原始值记录到UNDO表空间中,然后才修改数据块。

1.2 UNDO的核心用途

用途 说明
事务回滚(Rollback) 当用户执行ROLLBACK命令或事务异常中断时,Oracle使用UNDO数据将已修改的数据恢复到事务开始前的状态,保证事务的原子性
读一致性(Read Consistency) 当一个事务正在查询数据时,其他事务对同一数据的修改不会影响到当前查询的结果。 查询开始时记录当前SCN,如果读取的数据块SCN大于查询的SCN,Oracle从UNDO中找到该行的旧版本
闪回查询(Flashback Query) Oracle闪回查询(Flashback Query)、闪回事务(Flashback Transaction)、闪回版本查询(Flashback Version Query)等特性,都依赖UNDO表空间中保留的历史版本数据。
实例恢复(Instance Recovery) 数据库崩溃重启后,Oracle使用UNDO数据回滚未提交的事务,保证数据一致性

1.3 UNDO与REDO的区别

对比维度 UNDO REDO
记录内容 数据修改前的旧值(Before Image) 数据修改的操作(Change Vector)
主要用途 回滚事务、读一致性 前滚恢复、重演事务
产生时机 修改数据前记录 修改数据时记录
存储位置 UNDO表空间 联机重做日志文件

特别注意:记录UNDO数据时,同样需要产生redo日志!与其他业务表增删改时产生的redo日志没有任何区别!

二、UNDO的两种管理方式

Oracle数据库提供了两种UNDO管理方式:Manual Undo Management(手动UNDO管理)Automatic Undo Management(自动UNDO管理)

2.1 Manual Undo Management(手动UNDO管理)

在Oracle 9i之前,管理UNDO数据只能使用回滚段(Rollback Segment)。在这种模式下,UNDO空间通过回滚段外部进行分配,不使用UNDO表空间

特点:

  • DBA需要手动创建、管理和监控回滚段
  • 需要规划回滚段的数量和大小
  • 管理复杂,容易因回滚段不足导致事务失败
  • 通过参数UNDO_MANAGEMENT=MANUAL启用

备注:该管理模式,基本已经完全弃用

2.2 Automatic Undo Management(自动UNDO管理)

Oracle 9i引入了自动UNDO管理,通过UNDO表空间来管理UNDO段,消除了回滚段管理的复杂性。

特点:

  • 数据库自动管理UNDO段
  • 使用UNDO表空间管理和存储UNDO段
  • 自动调整UNDO保留时间
  • 大大简化了DBA的管理工作
  • 通过参数UNDO_MANAGEMENT=AUTO启用

强烈建议 :Oracle官方强烈推荐使用UNDO表空间而非回滚段来管理UNDO。在CDB中,UNDO_MANAGEMENT必须设置为AUTO

备注:现在全部都是使用这种自动undo管理方式!

三、UNDO表空间创建、删除、切换、扩容

3.1 创建UNDO表空间

基本语法

复制代码
CREATE UNDO TABLESPACE undo_tbs_name
    DATAFILE 'datafile_path' SIZE size
    [AUTOEXTEND ON NEXT increment_size MAXSIZE max_size]
    [RETENTION GUARANTEE];

参数说明

  • RETENTION NOGUARANTEE:默认值,当UNDO空间不足时,允许覆盖未过期的UNDO数据。
  • RETENTION GUARANTEE:保证未过期的UNDO数据不会被覆盖,即使导致DML事务失败(详见第六模块)。

注意事项

  • UNDO表空间必须使用本地管理(EXTENT MANAGEMENT LOCAL),不允许指定区管理方式,Oracle会自动采用AUTOALLOCATE
  • 不能在UNDO表空间中创建任何数据库对象(表、索引等)。
  • RAC环境中每个实例必须有独立的UNDO表空间,不允许共享

示例:

sql 复制代码
-- 创建50M的UNDO表空间,启用自动扩展
CREATE UNDO TABLESPACE undotbs2 
DATAFILE '/oradata/orcl/undotbs02.dbf' SIZE 50M 
AUTOEXTEND ON NEXT 20M MAXSIZE 500M;

-- 创建带RETENTION GUARANTEE的UNDO表空间
CREATE UNDO TABLESPACE undotbs3 
DATAFILE '/oradata/orcl/undotbs03.dbf' SIZE 20M
RETENTION GUARANTEE;

3.2 删除UNDO表空间

前提条件:不能删除当前正在使用的UNDO表空间。

sql 复制代码
-- 1. 先切换到其他UNDO表空间
ALTER SYSTEM SET UNDO_TABLESPACE = undotbs2;

-- 2. 确认切换完成
SHOW PARAMETER undo_tablespace;

-- 3. 删除旧的UNDO表空间
DROP TABLESPACE undotbs1 INCLUDING CONTENTS AND DATAFILES;

注意

1、在数据库中删除表空间后,数据文件可能仍在物理磁盘上存在,需要手动删除。

2、如果待删除的undo表空间中,还有未结束的活动事务,需要等待事务完成才可以删除。即表空间中所有UNDO段必须处于离线状态(所有事务已完成)

3.3 切换默认UNDO表空间

任意给定时刻只能使用一个UNDO表空间。

sql 复制代码
-- 切换默认UNDO表空间
ALTER SYSTEM SET UNDO_TABLESPACE = undotbs3;

3.4 扩容UNDO表空间

方法一:添加数据文件

sql 复制代码
ALTER TABLESPACE undotbs1 
ADD DATAFILE '/oradata/orcl/undotbs02.dbf' SIZE 1G 
AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法二:调整现有数据文件大小

sql 复制代码
ALTER DATABASE DATAFILE '/oradata/orcl/undotbs01.dbf' RESIZE 2G;

方法三:启用/调整自动扩展

sql 复制代码
ALTER DATABASE DATAFILE '/oradata/orcl/undotbs01.dbf' 
AUTOEXTEND ON NEXT 128M MAXSIZE 24G;

四、UNDO表空间使用

4.1 UNDO段(Undo Segment)

UNDO段是UNDO表空间中用于存储UNDO记录的逻辑结构。每个活跃的事务会分配到一个UNDO段,该事务的所有UNDO记录都写入这个UNDO段中。

特别注意:一个UNDO段可以同时支持多个事务!

4.2 UNDO段,区(extent)的状态

状态 说明
ACTIVE 正在被活跃事务使用,不可覆盖
UNEXPIRED 事务已提交但未超过UNDO_RETENTION,不可覆盖(除非空间不足)
EXPIRED 已超过UNDO_RETENTION,可以被覆盖
FREE(空闲) 未分配的UNDO空间

4.3 空间分配优先级

当新事务需要UNDO空间时,Oracle按以下顺序分配:

  1. 优先使用FREE空闲空间。
  2. 空闲空间不足时,使用EXPIRED已过期的UNDO空间。
  3. 已过期空间仍不足时,若未开启RETENTION GUARANTEE,会覆盖UNEXPIRED未过期的UNDO数据;若开启了GUARANTEE,则直接报错ORA-30036(无法扩展UNDO段)
sql 复制代码
-- 查看UNDO表空间中各段的状态
SELECT segment_name, tablespace_name, status 
FROM dba_rollback_segs 
WHERE tablespace_name = 'UNDOTBS1';

-- 查看UNDO区段的状态分布
SELECT status, SUM(bytes)/1024/1024 AS size_mb
FROM dba_undo_extents
WHERE tablespace_name = 'UNDOTBS1'
GROUP BY status;

五、UNDO Retention的意义

5.1 什么是UNDO_RETENTION

UNDO_RETENTION是一个初始化参数,用于指定UNDO数据保留的最低时间阈值 (单位:秒)。默认值为900秒(15分钟)。

  • 保障长时间运行的查询能够获取读一致性数据,避免ORA-01555错误。
  • 支撑闪回查询的时间范围,例如设置为3600秒,则支持查询1小时内的历史数据。
sql 复制代码
-- 查看当前UNDO_RETENTION
SHOW PARAMETER undo_retention;

-- 修改UNDO_RETENTION(动态生效)
ALTER SYSTEM SET UNDO_RETENTION = 1800;

5.2 不同场景下UNDO_RETENTION的生效规则

  • 自动扩展的UNDO表空间 :Oracle会尽量满足UNDO_RETENTION设定的保留时间,当空间不足时会自动扩展数据文件。
  • 固定大小的UNDO表空间(默认)UNDO_RETENTION仅作为参考值,当空间不足时,Oracle会自动缩短实际保留时间,优先保障DML事务的执行。
  • 开启RETENTION GUARANTEE的UNDO表空间:严格保证未过期的UNDO数据不会被覆盖,即使导致DML事务失败也不会妥协。

5.3 如何确保UNDO数据不被提前覆盖

方法一:使用RETENTION GUARANTEE

从Oracle 10g开始,可以使用RETENTION GUARANTEE选项,确保在定义的UNDO_RETENTION时间之前,UNDO信息不会被覆盖。

sql 复制代码
-- 创建时指定
CREATE UNDO TABLESPACE undotbs1 
DATAFILE '/path/undotbs01.dbf' SIZE 200M
RETENTION GUARANTEE;

-- 对现有表空间修改
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;

-- 取消GUARANTEE
ALTER TABLESPACE undotbs1 RETENTION NOGUARANTEE;

特别注意

1、如果设置UNDO表空间为RETENTION GUARANTEE,未过期的数据不会被覆盖。如果表空间空间不足,会导致DML操作失败或事务挂起

2、开启GUARANTEE后必须确保UNDO表空间容量足够,否则高并发DML场景下会频繁出现ORA-30036错误,导致业务事务失败

5.4 自动UNDO保留调优(Automatic Undo Retention Tuning)

从Oracle 10g开始,Oracle会根据UNDO表空间大小、UNDO生成速率、最长查询长度和RETENTION GUARANTEE设置等参数,自动调整UNDO保留时间 。设置的UNDO_RETENTION参数只是一个指导值,Oracle会自动调整UNDO保留时间以避免出现ORA-1555错误。

保留时间间隔依赖于估计最长的事务可能运行的时间长度。根据数据库中最长事务长度的信息,可以给UNDO_RETENTION分配一个大致的时间。可以通过v$undostat视图的maxquerylen列查询在过去的一段时间内,最长的查询执行的时间(以秒为单位)。UNDO_RETENTION参数中的时间会自动调整尽量大于等于maxquerylen列中给出时间值。

sql 复制代码
-- 查看系统自动调整后的实际UNDO保留时间
SELECT TO_CHAR(begin_time, 'DD-MON-RR HH24:MI') AS begin_time,
       TO_CHAR(end_time, 'DD-MON-RR HH24:MI') AS end_time,
       tuned_undoretention
FROM v$undostat
ORDER BY end_time;

类似如下:
BEGIN_TIME         END_TIME           TUNED_UNDORETENTION
------------------ ------------------ -------------------
05-AUG-26 14:02    05-AUG-26 14:12                   1172
05-AUG-26 14:12    05-AUG-26 14:22                   1782
05-AUG-26 14:22    05-AUG-26 14:32                   1186
05-AUG-26 14:32    05-AUG-26 14:42                   1733
05-AUG-26 14:42    05-AUG-26 14:52                  82995
05-AUG-26 14:52    05-AUG-26 15:02                  68969
05-AUG-26 15:02    05-AUG-26 15:02                  68969
其中,TUNED_UNDORETENTION列值,就是自动调整后undo的保留时间

六、如何评估所需UNDO大小

6.1 计算公式

评估UNDO表空间大小需要以下三个信息:

参数 说明
UR UNDO_RETENTION参数值(单位:秒)
UPS 每秒生成的UNDO数据块数量
DBS 数据库块大小(db_block_size

计算公式

复制代码
UndoSpace = [UR × (UPS × DBS)]

6.2 计算步骤

步骤1:确定UNDO_RETENTION

sql 复制代码
SHOW PARAMETER undo_retention;

步骤2:计算每秒UNDO块生成量(UPS)

sql 复制代码
-- 计算业务高峰期每秒产生的UNDO数据块数
SELECT MAX(undoblks / ((end_time - begin_time) * 24 * 3600)) AS ups
FROM v$undostat;

步骤3:获取数据库块大小

sql 复制代码
SHOW PARAMETER db_block_size;

步骤4:计算所需UNDO空间

sql 复制代码
SELECT (ur * (ups * dbs))  AS "Bytes"
FROM (SELECT value AS ur FROM v$parameter WHERE name = 'undo_retention'),
     (SELECT (SUM(undoblks) / SUM(((end_time - begin_time) * 86400))) AS ups 
      FROM v$undostat),
     (SELECT value AS dbs FROM v$parameter WHERE name = 'db_block_size');

示例计算

假设:

  • UNDO_RETENTION = 86400秒(24小时)

  • UPS = 11.305块/秒

  • db_block_size = 8192字节

    所需UNDO空间 = 11.305 × 86400 × 8192 / 1024 / 1024 / 1024 ≈ 7.45 GB

建议

1、一般应该在一天中数据库负载最繁重的时候 进行计算。同时参考UNDO表空间的平均使用情况和峰值使用情况

2、生产环境的UNDO表空间大小应设置为计算结果的1.2~1.5倍,预留缓冲空间应对突发负载。

6.3 使用Undo Advisor

Oracle提供了Undo Advisor工具,可以帮助评估所需的UNDO表空间容量。通过查询V$UNDOSTAT视图的TUNED_UNDORETENTION列,可以了解系统自动调优后的UNDO保留时间。

七、DML操作UNDO产生量分析

7.1 总体原则

一般规律

DML操作 UNDO产生量 原因
INSERT 最少 回滚INSERT只需要ROWID(行标识),相当于记录"删除这个ROWID"
UPDATE 中等 需要存储被修改列的旧值,修改的列越多、数据越大,UNDO越多
DELETE 最多 需要存储整条记录的完整旧值

7.2 原理解析

从回滚的角度理解:

  • 回滚INSERT → 执行DELETE(只需要ROWID即可定位并删除)
  • 回滚DELETE → 执行INSERT(需要整条记录的完整数据才能重新插入)
  • 回滚UPDATE → 执行反向UPDATE(需要记录被修改列的旧值)

7.3 索引的影响

索引的存在会显著改变UNDO的生成量

  • INSERT有索引的表:除了表数据外,每个索引的维护也会产生UNDO
  • UPDATE非索引列:只产生表数据的UNDO,相对较少
  • UPDATE索引列:需要记录索引列的旧值,UNDO量增加
  • DELETE有索引的表:需要维护所有索引,产生大量UNDO

因此,UNDO的生成量取决于操作的数据量、表的索引数量以及具体修改的内容

7.4 监控UNDO生成量

sql 复制代码
-- 查看系统级UNDO生成量
SELECT name, value 
FROM v$sysstat 
WHERE name = 'undo change vector size';

-- 查看当前会话的UNDO生成量
SELECT name, value 
FROM v$mystat m, v$statname s
WHERE m.statistic# = s.statistic# 
AND s.name = 'undo change vector size';

八、释放UNDO表空间

重建UNDO表空间(推荐)

sql 复制代码
-- 1. 创建新的UNDO表空间(设置合理大小)
CREATE UNDO TABLESPACE undotbs_new 
DATAFILE '/oradata/orcl/undotbs_new01.dbf' SIZE 500M
AUTOEXTEND ON NEXT 100M MAXSIZE 10G;

-- 2. 切换到新的UNDO表空间
ALTER SYSTEM SET UNDO_TABLESPACE = undotbs_new;

-- 3. 确认切换完成
SHOW PARAMETER undo_tablespace;

-- 4. 等待一段时间,确保旧UNDO表空间不再被使用
可通过查询DBA_UNDO_EXTENTS确认无ACTIVE状态的区
SELECT COUNT(*) FROM dba_undo_extents
WHERE tablespace_name = 'UNDOTBS_OLD' AND status = 'ACTIVE';

-- 5. 删除旧的UNDO表空间
DROP TABLESPACE undotbs_old INCLUDING CONTENTS AND DATAFILES;


-- 示例,释放UNDOTBS3 表空间
SQL> SHOW PARAMETER undo_tablespace;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_tablespace                      string      UNDOTBS3

SQL> CREATE UNDO TABLESPACE undotbs4 
  2  DATAFILE '/oradata/orcl/undotbs04.dbf' SIZE 50M 
  3  AUTOEXTEND ON NEXT 20M MAXSIZE 500M;
Tablespace created.

SQL> ALTER SYSTEM SET UNDO_TABLESPACE = 'UNDOTBS4';
System altered.

SQL> SELECT COUNT(*) FROM dba_undo_extents
  2  WHERE tablespace_name = 'UNDOTBS3' AND status = 'ACTIVE';
  COUNT(*)
----------
         0

SQL> DROP TABLESPACE UNDOTBS3 INCLUDING CONTENTS AND DATAFILES;
Tablespace dropped.

九、常用查询

9.1 UNDO常用数据字典和视图

视图/字典 说明
V$UNDOSTAT 监控UNDO表空间使用统计,每10分钟一条记录
V$TRANSACTION 查看当前活跃事务及其占用的UNDO资源
V$ROLLSTAT UNDO段的状态统计信息
V$ROLLNAME UNDO段的名称
DBA_ROLLBACK_SEGS 所有回滚段/UNDO段的信息
DBA_UNDO_EXTENTS UNDO表空间中区段(Extent)的详细信息,包含提交时间
DBA_TABLESPACES 表空间基本信息(含UNDO类型)(是否开启GUARANTEE等)

9.2 常用查询语句

查看UNDO表空间基本信息

sql 复制代码
-- 查看所有UNDO表空间
SELECT tablespace_name, status, contents 
FROM dba_tablespaces 
WHERE contents = 'UNDO';

-- 查看各UNDO表空间的大小
select df.tablespace_name,round(sum(df.bytes)/1024/1024/1024,2) as "size(gb)"
 from dba_data_files df
 where tablespace_name in 
 (SELECT tablespace_name
FROM dba_tablespaces 
WHERE contents = 'UNDO')
group by tablespace_name
order by 2 desc;

查看当前默认UNDO表空间

sql 复制代码
SHOW PARAMETER undo_tablespace;

查看UNDO表空间使用情况

sql 复制代码
--undo表空间实际使用情况 (推荐) 如果used_rag>60%需要查具体是哪个进程
--下面语句只查询ACTIVE undo段占用的使用率
set linesize 200
col used_pct format a8
select b.tablespace_name,
       nvl(used_undo,0) "USED_UNDO(M)",
       total_undo "Total_undo(M)",
       trunc(nvl(used_undo,0) / total_undo * 100, 2) || '%' used_PCT
  from (select nvl(sum(bytes / 1024 / 1024), 0) used_undo, tablespace_name
          from dba_undo_extents
         where status = 'ACTIVE'
         group by tablespace_name) a,
       (select tablespace_name, sum(bytes / 1024 / 1024) total_undo
          from dba_data_files
         where tablespace_name in
               (select value
                  from v$spparameter
                 where name = 'undo_tablespace'
                   and (sid = (select instance_name from v$instance) or
                       sid = '*'))
         group by tablespace_name) b
 where a.tablespace_name (+)= b.tablespace_name
/

--下面语句只查询ACTIVE和UNEXPIRED undo段占用的使用率
select b.tablespace_name,
       nvl(used_undo,0) "USED_UNDO(M)",
       total_undo "Total_undo(M)",
       trunc(nvl(used_undo,0) / total_undo * 100, 2) || '%' used_PCT
  from (select nvl(sum(bytes / 1024 / 1024), 0) used_undo, tablespace_name
          from dba_undo_extents
         where status in ( 'ACTIVE','UNEXPIRED')
         group by tablespace_name) a,
       (select tablespace_name, sum(bytes / 1024 / 1024) total_undo
          from dba_data_files
         where tablespace_name in
               (select value
                  from v$spparameter
                 where name = 'undo_tablespace'
                   and (sid = (select instance_name from v$instance) or
                       sid = '*'))
         group by tablespace_name) b
 where a.tablespace_name (+)= b.tablespace_name
/

查看UNDO表空间使用统计(V$UNDOSTAT)

sql 复制代码
SELECT TO_CHAR(begin_time, 'YYYY-MM-DD HH24:MI') AS begin_time,
       TO_CHAR(end_time, 'YYYY-MM-DD HH24:MI') AS end_time,
       tuned_undoretention AS tuned_retention_sec,
       maxquerylen AS max_query_length,
       unxpstealcnt AS unexpired_steal_count,
       expstealcnt AS expired_steal_count,
       ssolderrcnt AS ora_01555_count,
       nospaceerrcnt AS no_space_error_count
FROM v$undostat
ORDER BY end_time DESC;

关键字段说明:
tuned_undoretention:Oracle自动调优后的实际保留时间。
maxquerylen:统计周期内最长查询的执行时长。
unxpstealcnt:被迫覆盖未过期UNDO数据的次数,若大于0说明UNDO空间不足。
ssolderrcnt:ORA-01555错误出现次数。
nospaceerrcnt:ORA-30036错误出现次数。

查看UNDO表空间区段状态

sql 复制代码
-- 查看UNDO表空间中各状态区段的大小
SELECT tablespace_name, status,
       ROUND(SUM(bytes) / 1024 / 1024, 2) AS size_mb,
       COUNT(*) AS extent_count
FROM dba_undo_extents
GROUP BY tablespace_name, status
ORDER BY tablespace_name, status;

查看当前活跃事务的UNDO使用情况

sql 复制代码
-- 查看活跃事务占用的UNDO资源
SELECT r.name rbs,
       nvl(s.username, 'None') oracle_user,
       s.osuser client_user,
       p.username unix_user,
       s.sid,
       s.serial#,
       p.spid unix_pid,
       t.used_ublk * TO_NUMBER(x.value) / 1024 / 1024 as undo_mb ,
       TO_CHAR(s.logon_time, 'mm/dd/yy hh24:mi:ss') as login_time,
       TO_CHAR(sysdate - (s.last_call_et) / 86400, 'mm/dd/yy hh24:mi:ss') as last_txn,
       t.START_TIME transaction_starttime
 FROM v$process      p,
       v$rollname    r,
       v$session     s,
       v$transaction t,
       v$parameter x   
 WHERE s.taddr = t.addr   
   AND s.paddr = p.addr   
   AND r.usn = t.xidusn(+)   
   AND x.name = 'db_block_size'   
 ORDER by undo_mb desc
/
相关推荐
何以解忧,唯有..2 小时前
数据库索引失效的常见情况与优化策略
数据库·sql·oracle
这个DBA有点耶2 小时前
分布式数据库到底该不该上?从判断标准到架构选型的实战思考
数据库·架构·dba
01_ice3 小时前
MySQL库和表的操作
数据库·mysql
布莱克6054 小时前
数据库索引分类:数据结构、物理存储与逻辑角度详解
数据结构·数据库
SelectDB4 小时前
DeepSeek Harness 接入 Litefuse:完善 Agent 可观测与评估能力
数据库
这个DBA有点耶5 小时前
从库延迟的“二次放大”效应:一次大事务,拖垮整个读写分离
数据库·mysql·架构
LearnYard5 小时前
自然语言驱动的数据图表生成:几款工具功能对比实践
数据库·百度·powerpoint
一个有温度的技术博主5 小时前
MySQL 三大日志协同机制:redo log、undo log 与 binlog 的联合运作
数据库·mysql·oracle
ltl6 小时前
ClickHouse 与 DuckDB 选型:不是同一类列存
数据库