UNDO_RETENTION作用

OracleUndo机制中,参数Undo_Retention扮演了“混淆者”的角色。论坛里面也有很多朋友对这个参数含义不是非常清楚。本篇我们就来讨论一下这个这个参数的含义和作用。

 

1、从Undo说起

 

Undo或者说rollback segment机制是Oracle早期奠定行业地位的核心技术之一。Undo机制的提出,源自于Oracle提出的“多版本一致读”特性。在Oracle中,select操作不会阻塞任何操作,也不会被任何操作所阻塞。

 

这就意味着,当我们对一个数据表进行DML操作,比如插入、修改和删除数据的时候,其他会话连接的select操作是可以随意进行的,而且访问的数据都是DML操作之前提交的数据。

 

Oracle数据是保存在“表空间、段对象、分区和数据块”的组织结构体系中。对数据的修改就是在数据块中直接的修改。如果需要同时支持对之前数据的访问,比如在系统中有一个地方需要保存数据的“前镜像pre-image,同时一旦DML进行回滚rollback动作,恢复数据也需要这部分前镜像内容。这就衍生出了rollback segement和之后的Undo表空间。

 

那么,是不是当一个事务Transaction结束commit之后,Undo前镜像就没有用途了呢?我们说不是的。commit之后的undo段数据镜像至少要支持两种操作,其一是一致读(consistent read),另一个是利用undo数据的flash back闪回技术。

 

严格的说,多版本一致读是两个Oracle特性。一致读所说的是:当一个查询读操作select数据的时候,只能读取到小于等于启动查询操作时候SCN的数据。比如:我们启动查询的时候,数据表A中包括10亿条数据,。之后另一个会话启动删除了1亿条数据并且提交。提交之后,第一个读会话才检索到原来1亿条数据的位置,并且最后结束。从结果看,第一个会话读取到的是10亿条数据。

 

一致读特性的关键就在于保证了读操作的一致性,读取数据在时间层面的一致性。细想一下,第二个会话commit之后,源数据1亿条的前镜像在Undo空间中是失效Expired状态。一致读过程中,一定是进行过失效Undo镜像数据的读取。

 

失效Undo数据的最终归宿是被覆盖重用。想想一种情况,如果系统中Undo管理比较不合理,事务Undo数据量比较大而且频繁,有失效的Undo前镜像被覆盖之后,恰恰有一个长时间查询需要访问这个前镜像。这个时候,Oracle就只能说“抱歉”了,这也就是经典的ora-1555 snapshot too old的起源。

 

Undo失效数据的另一种用途就是Flashback闪回。Flashback QueryFlashback Archive都是建立在对前镜像数据再利用处理上。

 

Undo_RetentionOracle提供出的用于控制Undo过期数据保留的“调节Tune”参数。注意:这里不是控制参数Oracle中的控制参数起到强制作用,比如目录空间位置,归档文件存储等。但是另一部分参数起到的是目标调节的作用,比如检查点间隔控制、SGA_TARGET

 

 

SQL> show parameter undo_ret

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

undo_retention                       integer     900

SQL>

 

 

undo_retention从直接看就是设置Oracle Undo过期数据的保存期限,单位是秒。如果参数设置为900秒,那么Undo段数据在非Active状态之后,会保留900秒。

 

如果根据这个守则,我们进行一致读和Flashback的时间就是通过这个参数来进行控制的。但是事实上,这个是有问题的。Undo的覆盖动作是一个必然的过程,覆盖与否是要和系统事务Undo消耗速率、Undo Tablespace大小乃至Undo数据文件可拓展性密切相关。

 

事实上,Undo_retention是一个“目标期望值”。用户设置出这个值之后,Oracle内部会尽量保证将Undo数据保留超过undo_retention设置的时间。在这个过程中,Oracle会涉及到比如尝试拓展Undo表空间数据文件、Undo Segment管理等内容。但是,如果“现实比较残酷”,比如说Undo使用紧张、没有额外的方法,那么这个时间段也是不能保证的。

 

下面我们通过一系列的实验来验证。

 

2、环境准备

 

我们选择Oracle 11gR2进行测试实验。

 

 

SQL> select * from v$version;

BANNER

--------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production

PL/SQL Release 11.2.0.3.0 - Production

CORE        11.2.0.3.0         Production

 

 

当前采用自动的undo管理机制,默认retention900秒。注意:这个取值Oracle是有所选择的。早期版本中曾经设置过1800秒。

 

 

SQL> show parameter undo

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

undo_management                      string      AUTO

undo_retention                       integer     900

undo_tablespac                       string      UNDOTBS1

 

 

当前undo tablespace的数据文件拓展情况为支持拓展,容量为105M

 

 

SQL> col file_name for a40

SQL> select file_name, AUTOEXTENSIBLE, BYTES/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';

 

FILE_NAME                                AUTOEXTENSIBLE         MB

---------------------------------------- -------------- ----------

/u01/app/oradata/ORA11G/datafile/o1_mf_u YES                   105

ndotbs1_92t6zl6d_.dbf                                  

 

 

3、超过undo_retention情况数据读取

 

在没有强制的Undo数据覆盖情况下,Oracle默认会一直保留前镜像的数据。在实际中,虽然undo_retention设置的保留值比较小,但是我们依然可以flash back query出几个小时乃至几天前的数据。

 

为了便于实验过程,我们调节了一下参数。

 

 

SQL> alter system set undo_retention=300 ;

System altered

 

SQL> show parameter undo

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

undo_management                      string      AUTO

undo_retention                       integer     300

undo_tablespace                      string      UNDOTBS1

 

 

此处我们使用的是较大的Undo表空间105M,而且支持自动拓展文件。实验数据表情况如下:

 

 

SQL> create table t as select * from dba_objects;

Table created

 

SQL> select bytes/1024/1024 MB from dba_segments where wner='SYS' and segment_name='T';

        MB

----------

         9

 

SQL> select count(*) from t;

  COUNT(*)

----------

     75255

 

--注意:当前时点上,数据量为7万。

SQL> select sysdate from dual;

SYSDATE

--------------------

2013-10-16 8:46:57

 

 

删除数据。

 

 

SQL> delete t;

75255 rows deleted

 

SQL> commit;

Commit complete

 

 

经过十五分钟左右,注意这个时间已经远远超过900秒设置值。

 

 

SQL> select sysdate from dual;

 

SYSDATE

--------------------

2013-10-16 9:00:34

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

         0

 

SQL> select count(*) from t as of timestamp to_timestamp('2013-10-16 8:46:57','yyyy-mm-dd hh24:mi:ss');

 

  COUNT(*)

----------

     75255

 

 

超过了900秒,Undo前镜像依然保留而且可以访问到。到此我们可以得出结论,即使commit后超过了undo_retention设置的时间范围,前镜像数据依然可以读取到。

 

4、小Undo空间非拓展试验

 

下面我们看一下undo时间小于retention的情况。向实验数据表中插入实验数据。

 

 

SQL> insert into t select * from dba_objects;

75255 rows inserted

 

SQL> commit;

Commit complete

 

 

创建一个全新的undo tablespace注意设置文件大小比较小,而且不支持自动拓展。

 

 

SQL> create undo tablespace undotbs2 datafile size 20m autoextend off;

Tablespace created

 

SQL> select tablespace_name, contents from dba_tablespaces;

 

TABLESPACE_NAME                CONTENTS

------------------------------ ---------

SYSTEM                         PERMANENT

SYSAUX                         PERMANENT

UNDOTBS1                       UNDO

TEMP                           TEMPORARY

USERS                          PERMANENT

UNDOTBS2                       UNDO

EXAMPLE                        PERMANENT

 

7 rows selected

 

SQL> select file_name, AUTOEXTENSIBLE, BYTES/1024/1024 MB from dba_data_files where tablespace_name in ('UNDOTBS1','UNDOTBS2');

 

FILE_NAME                                AUTOEXTENSIBLE         MB

---------------------------------------- -------------- ----------

/u01/app/oradata/ORA11G/datafile/o1_mf_u YES                   105

ndotbs1_92t6zl6d_.dbf                                  

 

/u01/app/oradata/ORA11G/datafile/o1_mf_u NO                     20

ndotbs2_95vsgpn7_.dbf                                   

 

 

更换系统使用的undo tablespace参数。

 

 

SQL> alter system set undo_tablespace=undotbs2

  2  ;

 

System altered

 

SQL> show parameter undo;

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

undo_management                      string      AUTO

undo_retention                       integer     300

undo_tablespace                      string      UNDOTBS2

 

 

删除数据,形成镜像。

 

 

SQL> select sysdate from dual;

 

SYSDATE

--------------------

2013-10-16 9:18:57

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

     75255

 

SQL> delete t;

55256 rows deleted

 

SQL> commit;

Commit complete

 

 

下面我们试图去消耗大量的undo空间,DML操作中,delete是消耗最大的。

 

 

SQL> delete mmm where rownum<10000;

9999 rows deleted

 

SQL> commit;

Commit complete

 

SQL> delete mmm;

delete mmm

 

ORA-30036: 无法按 8 扩展段 (在还原表空间 'UNDOTBS2' )

 

 

SQL> delete mmm where rownum<10000;

9999 rows deleted

 

SQL> commit;

Commit complete

 

 

删除动作中,很多时候都是禁止的。因为Undo空间过小,不能容纳需要保存的前镜像数据。

 

 

SQL> select count(*) from t as of timestamp to_timestamp('2013-10-16 9:15:09','yyyy-mm-dd hh24:mi:ss');

 

select count(*) from t as of timestamp to_timestamp('2013-10-16 9:15:09','yyyy-mm-dd hh24:mi:ss')

 

ORA-01555: 快照过旧回退段号 12 (名称为 "_SYSSMU12_550256870$") 过小

 

SQL> select sysdate from dual;

 

SYSDATE

--------------------

2013-10-16 9:20:38

 

SQL> select count(*) from t as of timestamp to_timestamp('2013-10-16 9:17:09','yyyy-mm-dd hh24:mi:ss');

 

select count(*) from t as of timestamp to_timestamp('2013-10-16 9:17:09','yyyy-mm-dd hh24:mi:ss')

 

ORA-01555: 快照过旧回退段号 12 (名称为 "_SYSSMU12_550256870$") 过小

 

 

由此我们可以看到,虽然设置了undo_retention的参数,但是如果系统undo表空间容量不够大,而且undo生成总量很大的时候,系统还是会将undo进行覆盖。

 

那么,所谓的调节作用怎么体现呢?undo文件拓展是一种非常直接的手段。


5、小Undo空间可拓展实验

 

我们同样创建一个小表空间,但区别在于设置其可以进行空间拓展。

 

 

SQL> select sysdate from dual;

SYSDATE

--------------------

2013-10-16 9:27:02

 

SQL> select count(*) from t;

  COUNT(*)

----------

         0

 

SQL> select sysdate from dual;

SYSDATE

--------------------

2013-10-16 9:27:20

 

SQL> insert into t select * from dba_objects;

75256 rows inserted

 

SQL> commit;

Commit complete

 

 

修改表空间,此时工具表MMM大小为17万。

 

 

SQL> select count(*) from mmm;

 

  COUNT(*)

----------

171029

 

 

SQL> alter database datafile '/u01/app/oradata/ORA11G/datafile/o1_mf_undotbs2_95vsgpn7_.dbf' autoextend on;

 

Database altered

 

SQL> delete mmm;

171029 rows deleted

 

SQL> commit;

Commit complete

 

 

检查空间,我们发现undo表空间大小发生了变化。从原来的20M扩大到42M

 

 

 

SQL> select file_name, AUTOEXTENSIBLE, BYTES/1024/1024 MB from dba_data_files where tablespace_name in ('UNDOTBS1','UNDOTBS2');

 

FILE_NAME                                AUTOEXTENSIBLE         MB

---------------------------------------- -------------- ----------

/u01/app/oradata/ORA11G/datafile/o1_mf_u YES                   105

ndotbs1_92t6zl6d_.dbf                                  

 

/u01/app/oradata/ORA11G/datafile/o1_mf_u YES                    42

ndotbs2_95vsgpn7_.dbf                                  

 

 

此时,我们是可以查找到retention范围内的数据。

 

 

SQL> select sysdate from dual;

 

SYSDATE

--------------------

2013-10-16 9:39:38

 

SQL> select count(*) from t as of timestamp to_timestamp('2013-10-16 9:27:20','yyyy-mm-dd hh24:mi:ss');

 

  COUNT(*)

----------

         0

 

 

在这个过程中,Oracle依然会遇到覆盖失效undo空间的问题。结合undo_retention参数,系统可以做到通过拓展Undo表空间来实现对原有undo的不覆盖现象。所以,Undo表空间容量从20M增长到现在的47M,同时undo_retention所设置的时间也得到保留。

 

综合上面的实验,我们可以判断出undo_retention参数本质上是一个advisor参数。我们通过参数时间的设置,告诉Oracle说我们希望维持一个多长时间的undo保留期间。针对这个期望,Oracle会去进行调节和空间拓展动作。这个过程是一个可选择的过程,如果现实条件存在限制,即使设置了retention期间,也难以保留。

 

那么,有没有强制保留的方法呢?如果确实存在业务要求需要前镜像留存,我们从10g开始就可以使用undo retentionguarntee机制来进行保护。

 

6Undo Retention Guarntee

 

Undo Retention Guarntee是针对undo tablespace设置的一种保护机制。通常情况下,undo_retention设置的时间是一个非强依赖。通过设置undo表空间的guarntee属性,我们可以保证对应的undo空间不被覆盖回收。

 

实验数据准备。

 

 

SQL> insert into mmm select * from dba_objects;

75256 rows inserted

 

SQL> insert into mmm select * from mmm;

75256 rows inserted

 

SQL> insert into mmm select * from mmm;

150512 rows inserted

 

SQL> commit;

Commit complete

 

 

创建一个表空间,设置为guarntee

 

 

SQL> create undo tablespace undotbs3 datafile size 10M autoextend off retention guarantee;

 

Tablespace created

 

SQL> select tablespace_name, contents, retention from dba_tablespaces where contents='UNDO';

 

TABLESPACE_NAME                CONTENTS  RETENTION

------------------------------ --------- -----------

UNDOTBS1                       UNDO      NOGUARANTEE

UNDOTBS2                       UNDO      NOGUARANTEE

UNDOTBS3                       UNDO      GUARANTEE

 

SQL> select file_name, AUTOEXTENSIBLE, BYTES/1024/1024 MB from dba_data_files where tablespace_name in ('UNDOTBS1','UNDOTBS2','UNDOTBS3');

 

FILE_NAME                                AUTOEXTENSIBLE         MB

---------------------------------------- -------------- ----------

/u01/app/oradata/ORA11G/datafile/o1_mf_u YES                   105

ndotbs1_92t6zl6d_.dbf                                  

 

/u01/app/oradata/ORA11G/datafile/o1_mf_u YES               44.9375

ndotbs2_95vsgpn7_.dbf                                  

 

/u01/app/oradata/ORA11G/datafile/o1_mf_u NO                     10

ndotbs3_95vw1v91_.dbf                                  

 

 

修改参数,启用undotbs3表空间。

 

 

SQL> alter system set undo_tablespace=undotbs3;

System altered

 

SQL> show parameter undo;

 

NAME                                 TYPE        VALUE

--------------------------------- ----------- ------------------------------

undo_management                      string      AUTO

undo_retention                       integer     300

undo_tablespace                      string      UNDOTBS3

 

 

下面进行空间实验。

 

 

SQL> select sysdate from dual;

 

SYSDATE

--------------------

2013-10-16 9:51:56

 

SQL> select count(*) from mmm;

 

  COUNT(*)

----------

    301024

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

     75256

 

SQL> delete t where rownum<10;

 

9 rows deleted

 

SQL> commit;

 

Commit complete

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

     75247

 

 

此时我们发现,如果发现可能会覆盖在undo_retention期间数据的语句,Oracle会直接拒绝操作。

 

 

SQL> delete mmm;

delete mmm

 

ORA-30036: 无法按 8 扩展段 (在还原表空间 'UNDOTBS3' )

 

 

SQL> alter tablespace undotbs3 retention noguarantee;

Tablespace altered

 

SQL> alter tablespace undotbs3 retention guarantee;

alter tablespace undotbs3 retention guarantee

 

ORA-30036: 无法按 8 扩展段 (在还原表空间 'UNDOTBS3' )

 

 

7、结论

 

Oracle Undo机制中,undo_retention是一个非常不容易理解的参数项。简单的说,undo_retention就是用户使用Oracle过程中,对flashback和一致读的基本要求期间。设置之后,Oracle会根据自动undo管理的原则进行调节,进行空间拓展,来适应实现用户的期间要求。

 

所谓“巧妇难为无米之炊”,undo_retention是用户的期望。Oracle在进行调节过程中,会根据实际的业务频繁度和数量量、以及undo表空间设置情况进行综合评估。就是说,虽然用户设置了undo_retention的期望,在很多情况下也是不能达到的。

 

如果业务场景中真正需要进行retention period的保留,可以使用undo表空间的guarantee方法。一旦设置这个参数开关,undo_retention就成为一个强依赖参数。Oracle在这种情况下,宁可拒绝SQL DML操作,也不会允许将undo数据前镜像覆盖的情况发生。


你可能感兴趣的:(Oracle数据库)