一、undo说明
undo表空间对Oracle来说,它保存的数据的前镜像,即修改之前的内容。它是非常重要的一个表空间。
undo的作用:
(1)rollback
(2)recover
(3)一致性读
(4)Flashback
二、Undo表空间的两种管理方式
Oracle的UNDO有两种方式:一是使用undo表空间,二是使用回滚段。
我们通过undo_management参数来控制使用哪种方式,如果设置为auto,就是使用undo表空间,这时必须要指定一个undo表空间。如果设为manual,系统启动后使用rollback segment方式存储undo信息。
SQL> show parameter undo;
NAME TYPE VALUE
--------------------------------- ----------- ------------------------------
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDOTBS1
如果系统没有指定undo_management,那么系统默认以manual方式启动,即使设置了auto方式的参数,这些参数也将被忽略。
当实例启动的时候,系统自动选择一个有效的undo表空间或者是rollback segment,如果没有有效的可用的undo表空间或者回滚段,系统使用system rollback segment。这是系统不推荐的。
1、当使用rollback segment时
当undo_management被设置成menual时使用系统回滚段,即将undo records记录到system表空间下的system段。
SQL> col segment_name format a10
SQL> select segment_name,tablespace_name,bytes,next_extent from dba_segments where segment_type='ROLLBACK';
SEGMENT_NA TABLESPACE_NAME BYTES NEXT_EXTENT
---------- ------------------------------ ---------- -----------
SYSTEM SYSTEM 393216 57344
通过上面的这条语句,我们可以查到这个用户rollback的system segment存在于system表空间。默认情况下,只有一个segment,并且它还比较小,所以,如果使用system段来存储undo records。肯定会影响数据库的性能。所以Oracle是建议使用undo tablespace 来管理undo records。
2、使用undo表空间
当undo_management设置成AUTO时使用undo tablespace来管理回滚段。这个时候,我们将有很多个undo segment,并且这些segment是存放在undo表空间里的。
SQL> select segment_name,tablespace_name,bytes,next_extent from dba_segments where segment_type='TYPE2 UNDO';
SEGMENT_NAME TABLESPACE_NAME BYTES NEXT_EXTENT
------------------------------ ------------------------------ ---------- -----------
_SYSSMU1_3724004606$ UNDOTBS1 2228224 65536
_SYSSMU2_2996391332$ UNDOTBS1 8519680 65536
_SYSSMU3_1723003836$ UNDOTBS1 1179648 65536
_SYSSMU4_1254879796$ UNDOTBS1 2228224 65536
_SYSSMU5_898567397$ UNDOTBS1 8519680 65536
_SYSSMU6_1263032392$ UNDOTBS1 1179648 65536
_SYSSMU7_2070203016$ UNDOTBS1 8519680 65536
_SYSSMU8_517538920$ UNDOTBS1 8519680 65536
_SYSSMU9_1650507775$ UNDOTBS1 2228224 65536
_SYSSMU10_1197734989$ UNDOTBS1 1179648 65536
10 rows selected
通过以上SQL的查询结果,我们可以看出,有10个undo segment来存放undorecords。
也可以通过查看v$rollstat和v$rollname两个视图来查看信息。这2个视图会显示所有rollback段的信息。包括system段和undo段。
SQL> select s.usn,n.name,s.extents,s.hwmsize,s.status from v$rollname n,v$rollstat s where s.USN=n.usn;
USN NAME EXTENTS HWMSIZE STATUS
---------- ------------------------------ ---------- ---------- ---------------
0 SYSTEM 6 385024 ONLINE
1 _SYSSMU1_3724004606$ 4 396812288 ONLINE
2 _SYSSMU2_2996391332$ 3 75882496 ONLINE
3 _SYSSMU3_1723003836$ 3 19128320 ONLINE
4 _SYSSMU4_1254879796$ 4 35774464 ONLINE
5 _SYSSMU5_898567397$ 3 175235072 ONLINE
6 _SYSSMU6_1263032392$ 3 16900096 ONLINE
7 _SYSSMU7_2070203016$ 3 76668928 ONLINE
8 _SYSSMU8_517538920$ 3 339533824 ONLINE
9 _SYSSMU9_1650507775$ 4 10608640 ONLINE
10 _SYSSMU10_1197734989$ 3 51503104 ONLINE
11 rows selected
3、undo_retention和retention guarantee参数
统计undo表空间的空闲和非空闲比例:
SQL> select tablespace_name,status,SUM(bytes)/1024/1024 "Bytes(M)" from dba_undo_extents group by tablespace_name,status;
TABLESPACE_NAME STATUS Bytes(M)
------------------------------ --------- ----------
UNDOTBS1 UNEXPIRED 38.0625
UNDOTBS1 EXPIRED 4.1875
我们看到查询的结果,unexpected和expired是已使用的undo表空间,其中expired说明是已经过期的数据,也就是15分钟(默认情况)以外的数据,以被覆盖,可以认为是空闲的。
这里就关系到一个参数:undo_retention,该参数用来指定undo记录保存的最长事件,一秒为单位,是个动态参数,完全可以再实例运行时随时修改,通常默认是900秒,也就是15分钟。
undo_retention只是指定undo数据的过期时间,并不是说,undo中的数据一定会在undo表空间中保存15分钟,比如说刚一个新事物开始的时候,如果undo表空间已经被写满,则新事务的数据就会自动覆盖已提交的数据,而不管这些数据是否已经过期,因此,再创建undo表空间的时候一定要有足够的空间。
undo_retention中指定的时间一过,以提交事务中的数据就立刻无法访问,它只是失效,只要不被别的事务覆盖,它会仍然存在,并可随时被flashback特性引用。如果undo表空间足够大,而数据库又不是特别繁忙,那么其实undo_retention参数的值并不会影响到你,哪怕你设置成1,只要没有事务去覆盖undo数据,它就会持续有效。总之,要注意undo表空间的大小,保证有足够的空间。
只有在一种情况下,undo表空间能确保undo中的数据在undo_retention指定时间过期前一定有效,就是为undo表空间指定Retention Guarantee,指定之后,oracle对于undo表空间中未过期的undo数据不会覆盖,例如:
SQL> alter tablespace undotbs1 retention guarantee;
表空间已更改。
禁止undo表空间retention guarantee.
SQL> alter tablespace undotbs1 retention noguarantee;
表空间已更改。
undo表空间是会被重用的,只有当事务没有结束,或者开了retention guarantee,或在undo_retention时间内不能被重用。
在undo_retention规定的时间内,数据都是有效的,过期后都会设为无效,状态被改为expired,这些回滚段将会被看做Free Space。但是只要数据没有被覆盖就可以使用。如果空间已满,新事务的数据会自动覆盖掉已经提交的事务数据,即使在undo_retention的时间内。除非指定Retention Guarantee模式,才能保证在undo_retention内不被覆盖。
4、undo表空间满时的处理方法
默认情况下的Undo_retention只有15分钟,这个默认值,一般都无法满足系统的要求,一般建议改成3个小时。
SQL> alter system set undo_retention=10800;
undo_retention设置的越大,所需要的undo tablespace也就越大。
4.1、先模拟UNDO表空间满的情况
SQL> create undo tablespace undotbs2 datafile '/u01/app/oracle/oradata/orcl/undotbs02.dbf' size 1M;
Tablespace created.
SQL> alter tablespace undotbs2 retention guarantee;
Tablespace altered.
SQL> alter system set undo_tablespace=undotbs2;
System altered.
SQL> create table dba(id number);
Table created.
SQL> begin
2 for i in 1 .. 100000 loop
3 insert into dba values(i);
4 commit;
5 end loop;
6 end;
7 /
begin
*
ERROR at line 1:
ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS2'
ORA-06512: at line 3
4.2处理方法
1)增加undo表空间的数据文件
2)切换undo tablespace,这种情况下多用在undo表空间已经非常大的情况。
1)增加数据文件
SQL> alter tablespace undotbs2 add datafile '/u01/app/oracle/oradata/orcl/undotbs02a.dbf' size 100M reuse;
Tablespace altered.
SQL> begin
2 for i in 1 .. 100000 loop
3 insert into dba values(i);
4 commit;
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
2)切换UNDO表空间
1、建立新的表空间undotbs3
SQL> create undo tablespace undotbs3 datafile '/u01/app/oracle/oradata/orcl/undotbs03a.dbf' size 100M reuse;
Tablespace created.
2、切换到新建的undo表空间
SQL> alter system set undo_tablespace=undotbs3 scope=both;
3、将原来的undo表空间脱机
SQL> alter tablespace undotbs2 offline;
4、删除原来的undo表空间:
SQL> drop tablespace undotbs2 including contents and datafiles cascade constraints;
如果只是drop tablespace undo,则只会在删除控制文件中的记录,并不会删除物理文件。
Drop undo表空间时必须在未使用的情况下才能进行,如果undo表空间爱你正在使用,那么drop表空间命令将失败,在drop表空间的时候可以使用including contents。
4.3、undo表空间损坏的处理方法
出现undo损坏的情况,大都是因为异常宕机,在启动的时候报错,DB不能启动。
比如:ORA-00600:internal error code,arguments:[4194]
当alert log中出现ORA-600+[4194]时,基本就可以断定,是undo表空间出现了损坏。对于undo表空间的损坏,能备份恢复最好,不能的话建议使用如下方法
方法一:使用system segment
当我们使用undo表空间出现损坏时,可以先用system segmet启动DB,启动之后,在重新创建undo表空间,再用undo启动,步骤如下:
(1)用spfile创建spfile,然后修改参数:
#*.undo_tablespace='UNDOTBS3'
undo_management='MANUAL'
rollback_segments='SYSTEM'
(2)用修改后的pfile,重启DB
SQL> startup pfile='/u01/app/oracle/product/11.2.0/db_1/dbs/initPROD.ora'
SQL> show parameter undo;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management stringMANUAL
undo_retention integer10800
undo_tablespace string
(3)删除原来的表空间,创建新的undo表空间
SQL> drop tablespace undotbs3;
SQL> create undo tablespace undotbs03 datafile '/u01/app/oracle/oradata/orcl/undotbs03b.dbf' size 10M;
(4)关闭数据库,修改pfile参数,然后用心的pfile创建spfile,在正常启动数据库。
*.undo_retention=10800
*.undo_tablespace='UNDOTBS03'
方法二、跳过损坏的segment
通过alter log来查看正在使用的哪些segment,这些段有可能损坏。我们需要把这些损坏的segment跳过,先正常启动DB,在创建新的undo表空间,在切换一下。
(1)修改pfile,添加参数:
*._corrupted_rollback_segments='_SYSSMU11$','_SYSMU12$','_SYSSMU13$'
这些字段的值,我们可以通过alert log查看。
#strings system01.dbf | grep _SYSSMU | cut -d $ -f l | sort -u
(2)用修改之后的pfile启动DB
因为跳过了那些损坏的segment,所以DB可以正常启动。
(3)创建新的UNDO表空间,并切换过来
SQL>create undo tablespace undotbs1 datafile '/u01/app/oracle/oradata/orcl/undotbs1.dbf' size 10M;
SQL>alter system set undo_tablespace=undotbs1;
SQL>drop tablespace undotbs;
(4)修改pfile,创建spfile,并正常启动
删除:
*._corrupted_rollback_segments='_SYSSMU11$','_SYSMU12$','_SYSSMU13$'