1、重要概念
并行 DML 和 DDL 操作实际上可导致事务处理使用多个还原段。
还原段由 SYS 自动创建并始终归其所有。由于还原段充当循环缓冲区,因此每个段最少包含两个区。
还原表空间只在实例处于 MOUNT 状态时才可恢复
除非启用了保留时间保证,否则系统会忽略 UNDO_RETENTION。
UNDO_RETENTION 参数指定已提交的 Undo 信息要保留多长时间(单位为秒),默认为 900 秒(即 15 分钟)。但是该值不是绝对的,也就是说,如果有其它事务需要 Undo 空间,而 Undo 空
间出现不足时,这些信息仍然会被覆盖。为 只有当表空间设置为 GUARANTEE 时,才能确保已提交留 的数据保留 UNDO_RETENTION 参数设置的时间。RETENTION GUARANTEE 是表空间属性而不是初
始化参数,此属性只可使用 SQL 命令行语句来更改。
---通过更改 Undo 表空间来保证保留时间的语法是:
SQL>ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;
---要将有保留时间保证的还原表空间返回到其常规设置,请使用以下命令:
SQL>ALTER TABLESPACE undotbs1 RETENTION NOGUARANTEE;
---查询保留时间状态:
SQL> SELECT RETENTION FROM DBA_TABLESPACES WHERE TABLESPACE_NAME LIKE 'UNDO%';
如果设置 UNDO_RETENTION 为 0,那么 Oracle 启用自动调整 UNDO_RETENTION(auto tuning of undo_retention)以满足最长运行查询的需要,在告警日志文件中可以看到如下信息:
Autotune of undo retention is turned on.
可以通过设置“"_undo_autotune"=FALSE”来显式的关闭自动调整 UNDO_RETENTION 功能。

Undo 主要有以下几个作用:
(1) 事务回滚( (Rollback Transaction)
(2) 事务恢复( (Transaction Recovery)
(3) 提供一致性读(Consistent Read)
---Undo 数据是如何实现一致性读的呢?
在 Oracle 数据库中的 Buffer Cache 中的数据块上都会有最后一次修改数据块时的 SCN。如果一个事务需要修改数据块中数据,那么会先在回滚段中保存一份修改前数据和 SCN 的数据块,然后再更新
Buffer Cache 中的数据块的数据及其 SCN,并标识其为“脏”数据。当其它进程读取数据块时,会先比较数据块上的 SCN 和自己发出 SQL 语句时刻的 SCN,分为以下两种情况: 1 如果该数据块头部的 ITL 槽上记录的 SCN 大于自己查询时刻的 SCN,那么表示该块被更新过,此时就要借助 Undo 块了。在该数据块头部的 ITL 槽上记录了对应的 Undo 块的地址(Uba),
根据 Uba 就可以找到对应的 Undo 块。如果发现该 Undo 块的 ITL 槽的 SCN 号也较大,证明该 Undo 块也不可用,那么需要在该块的 ITL 槽上继续寻找上一个 Undo 块地址,层层递归,
最终找到 SCN 号比发出查询的 SCN 号小的Undo 块,将该 Undo 块中的被修改前的数据取出,从而构建出发出 SQL 语句时刻的数据块内容,这样的数据块叫做 CR(Consistent Read)块。
但是在查找的过程中,可能会发现当前 Undo 块里记录的 ITL 槽的 SCN号比上一个 Undo 块里记录的 SCN 号还要大。这种情况说明由于事务被提交或回滚,导致当前找到的 Undo块里的数据已经被其它
事务覆盖了,于是就无法再找出小于等于发出查询时的那个时间点的 SCN 号,这时Oracle 就会抛出一个非常经典的错误--ORA-1555,也就是 snapshot too old(快照过旧)的错误。
对于DELETE 来说,其 Undo 信息就是 INSERT,也就是说该构建出来的 CR 块中就插入了被删除的那条记录。 2 如果数据块头部的 ITL 槽(事务槽)上记录的 SCN 小于等于自己查询时刻的 SCN,那么分为两种情况:第一,若被查询的块上没有活动的事务,则表示该块没有被更新过,是可用的,可以直接读取该数 据块上的数据;第二,若被查询的块上有活动的事务,则需要找 Undo 的前镜像数据。
---Undo 段存储的内容 Redo 中只会记录少量信息,这些信息足以重演事务;同样 Undo 中也只记录精简信息,这些信息足以撤销事务。具体来说: 对于 INSERT 操作,回滚段只需要记录插入记录的 ROWID,如果回退,那么只需将该记录根据ROWID 删除即可; 对于 UPDATE 操作,回滚段只需要记录被更新字段的旧值即可(前镜像),回退时通过旧值覆盖新值即可完成回滚; 对于 DELETE 操作,Oracle 则必须记录整行的数据,在回滚时,Oracle 通过一个反向操作恢复删除的数据。 总结一下:常 对于相同数据量的数据操作,通常 INSERT 产生最少的 Undo ,UPDATE 产生的 Undo 居中,而 而 DELETE 操作产生的 Undo 最多。所以,当一个大的 DELETE 操作失败或者回滚,
总是需要很长的时间,并且会有大量的 Redo 生成。所以通常在进行大规模数据删除操作时,推荐通过分批删除分次提交,以减少对于回滚段的占用和冲击
块清除(Block Cleanout)是指清除存储在数据块头部与锁相关的信息,其实质是在清除块上的事务信息,包括数据的行级锁和 ITL 信息(包括提交标志、SCN 等),块清除不需要生成 Redo 日志。
Oracle 的块清除有两种: 快速块清除(Fast Commit Cleanout) )和 延时块清除(Delayed Block Cleanout) )。 建议在批量加载了数据后,通过运行 DBMS_STATS 实用程序来收集统计信息,就能自然的完成块清除工作。Oracle 提供了一个内部事件(10203 事件)可以用来跟踪数据库的块清除操作,可以通过以 下命令设置: ALTER SYSTEM SET EVENTS '10203 trace name context forever';
Oracle Undo 段中区有 3 种状态(DBA_UNDO_EXTENTS 的 STATUS 列):ACTIVE、EXPIRED 和UNEXPIRED: ACTIVE 即未提交的 Undo 信息(活动):表示事物还在活动,该值对应的 Undo 段的DBA_ROLLBACK_SEGS.STATUS 一定是 ONLINE 状态,一旦没有活动的事务在使用 Undo 段,那么对 应的 Undo 段就变成 OFFLINE 状态。ACTIVE 状态的 Undo 区不会被覆盖。 EXPIRED 即过期的 Undo 信息(过期):表示事务已经提交且超过了 UNDO_RETENTION 指定时间,该状态可以被覆盖使用。 UNEXPIRED 即提交的 Undo 信息(未过期):表示事务已经提交但是还没有超过UNDO_RETENTION 指定时间,该状态可以被覆盖使用。
自动Automatic Undo Retention Tuning 这个特性。设置的 undo_retention 参数只是一个指导值,,Oracle 会自动调整 Undo (会跨过 undo_retention 设定的时间) 来保证不会出现 Ora-1555 错误.
通过查询V$UNDOSTAT(该视图记录4天以内的UNDO表空间使用情况,超过4天可以查询DBA_HIST_UNDOSTAT视图) 的 tuned_undoretention (该字段在10G版本才有,9I是没有的)字段可以得到Oracle
根据事务量(如果是文件不可扩展,则会考虑剩余空间)采样后的自动计算出最佳的 retenton 时间.。这样对于一个事务量分布不均匀的数据库来说,,
就会引发潜在的问题--在批处理的时候可能 Undo 会用光, 而且这个状态将一直持续, 不会释放。
查询tuned_undoretention: select to_char(begin_time,'DD-MON-RR HH24:MI') begin_time,to_char(end_time,'DD-MON-RR HH24:MI') end_time,tuned_undoretention from v$undostat order by end_time; 检查一天平均每秒产生的UNDO BLOCK select (sum(undoblks)/sum((end_time-begin_time)*86400) from v$undostat; 生成的结果是UNDO BLOCK,如果需要计算出实际大小,则需要乘以db_block_size(通过show parameter db_block_size查出来) ---计算合适的UNDO表空间大小: select (UR*(UPS*DBS))+(DBS*24) as "bytes" from (select values as UR from v$parameter where name='undo_retention'),(select (sum(undoblks)/sum(((end_time-begin_time)*86400))) as ups from v$undostat),(select values as DBS from v$parameter where name='db_block_size');
ORA-01555 When Max Query Length Is Less Than Undo Retention, small or 0 Seconds (Doc ID 1131474.1)
set pagesize 25 set linesize 100 column UNXPSTEALCNT heading "# Unexpired|Stolen" column EXPSTEALCNT heading "# Expired|Reused" column SSOLDERRCNT heading "ORA-1555|Error" column NOSPACEERRCNT heading "Out-Of-space|Error" column MAXQUERYLEN heading "Max Query|Length" select inst_id, to_char(begin_time,'MM/DD/YYYY HH24:MI') begin_time, UNXPSTEALCNT, EXPSTEALCNT , SSOLDERRCNT, NOSPACEERRCNT, MAXQUERYLEN, TUNED_UNDORETENTION from gv$undostat order by inst_id, begin_time;
SELECT OWNER,SEGMENT_NAME,BYTES/1024/1024 MB FROM DBA_SEGMENTS WHERE TABLESPACE_NAME='UNDOTBS1'; SELECT * FROM DBA_ROLLBACK_SEGS; SELECT * FROM V$ROLLNAME; SELECT * FROM DBA_UNDO_EXTENTS; SELECT TABLESPACE_NAME, STATUS, SUM(BYTES) / 1024 / 1024 "Bytes(M)" FROM DBA_UNDO_EXTENTS GROUP BY TABLESPACE_NAME, STATUS; SELECT R.STATUS "Status", R.SEGMENT_NAME "Name", R.TABLESPACE_NAME "Tablespace", S.EXTENTS "Extents", TO_CHAR((S.BYTES / 1024 / 1024), '99999990.000') "Size" FROM SYS.DBA_ROLLBACK_SEGS R, SYS.DBA_SEGMENTS S WHERE R.SEGMENT_NAME = S.SEGMENT_NAME AND S.SEGMENT_TYPE IN ('ROLLBACK', 'TYPE2 UNDO') ORDER BY 5 DESC; SELECT R.NAME 回滚段名, S.SID SID, S.SERIAL# SERIAL, S.USERNAME 用户名, S.MACHINE 机器名, T.START_TIME 开始时间, T.STATUS 状态, T.USED_UBLK 撤消块, USED_UREC 撤消记录, T.CR_GET 一致性取, T.CR_CHANGE 一致性变化, T.LOG_IO "逻辑 I/O", T.PHY_IO "物理 I/O", T.NOUNDO NOUNDO, G.EXTENTS EXTENTS, SUBSTR(S.PROGRAM, 1, 50) 操作程序 FROM V$SESSION S, V$TRANSACTION T, V$ROLLNAME R, V$ROLLSTAT G WHERE T.ADDR = S.TADDR AND T.XIDUSN = R.USN AND R.USN = G.USN ORDER BY T.USED_UBLK DESC;