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的区别

对比维度UNDOREDO
记录内容数据修改前的旧值(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表空间,不允许共享

示例:

-- 创建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表空间。

-- 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表空间。

-- 切换默认UNDO表空间
ALTER SYSTEM SET UNDO_TABLESPACE = undotbs3;

3.4 扩容UNDO表空间

方法一:添加数据文件

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

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

ALTER DATABASE DATAFILE '/oradata/orcl/undotbs01.dbf' RESIZE 2G;

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

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段)
-- 查看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小时内的历史数据。
-- 查看当前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信息不会被覆盖。

-- 创建时指定
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列中给出时间值。

-- 查看系统自动调整后的实际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表空间大小需要以下三个信息:

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

计算公式

UndoSpace = [UR × (UPS × DBS)]

6.2 计算步骤

步骤1:确定UNDO_RETENTION

SHOW PARAMETER undo_retention;

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

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

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

SHOW PARAMETER db_block_size;

步骤4:计算所需UNDO空间

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生成量

-- 查看系统级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表空间(推荐)

-- 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$ROLLSTATUNDO段的状态统计信息
V$ROLLNAMEUNDO段的名称
DBA_ROLLBACK_SEGS所有回滚段/UNDO段的信息
DBA_UNDO_EXTENTSUNDO表空间中区段(Extent)的详细信息,包含提交时间
DBA_TABLESPACES表空间基本信息(含UNDO类型)(是否开启GUARANTEE等)

9.2 常用查询语句

查看UNDO表空间基本信息

-- 查看所有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表空间

SHOW PARAMETER undo_tablespace;

查看UNDO表空间使用情况

--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)

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表空间区段状态

-- 查看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使用情况

-- 查看活跃事务占用的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
/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值