Oracle 的Undo有两种方式: 一是使用undo 表空间,二是使用回滚段.
我们通过 来控制使用哪种方式,就使用UNDO 表空间,这时必须要指定一个UNDO 表空间。 系统启动后使用rollback segment方式存储undo信息。如果系统没有指定undo_management,那么系统默认以manual方式启动,即使设置了auto方式的参数,这些参数将被忽略。
当实例启动的时候,系统自动选择第一个有效的undo表空间或者是rollback segment,这种情况是不被推荐的,当系统运行在没有undo的情况下,系统会在alert.log中记录一条警告信息。
SQL> show parameter undo
NAME TYPE VALUE
------------------------------------ ----------- ------------------
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDOTBS1
下面来看一下undo 的表空间管理。先来查看一下表空间的使用情况:
/* Formatted on 2010/6/23 9:46:58 (QP5 v5.115.810.9015) */
SELECT a.tablespace_name,
ROUND (a.total_size) ,
ROUND (a.total_size) - ROUND (b.free_size, 3) ,
ROUND (b.free_size, 3) ,
ROUND (b.free_size / total_size * 100, 2) || free_rate
FROM ( SELECT tablespace_name, SUM (bytes) / 1024 / 1024 total_size
FROM dba_data_files
GROUP BY tablespace_name) a,
( SELECT tablespace_name, SUM (bytes) / 1024 / 1024 free_size
FROM dba_free_space
GROUP BY tablespace_name) b
WHERE a.tablespace_name = b.tablespace_name(+);
TABLESPACE_NAME total_size(MB) used_size(MB) free_size(MB) FREE_RATE
-------------------- -------------- ------------- ------------- --------------
SYSAUX 580 545.187 34.813 6%
DAVE 20 6.25 13.75 68.75%
USERS 10 8.375 1.625 16.25%
SYSTEM 960 951.062 8.938 93%
从结果我们看到UNDO 表空间已经用了23.875M。 我们看一下这使用的23M空间里空闲和非空闲比例:
/* Formatted on 2010/6/23 9:49:53 (QP5 v5.115.810.9015) */
SELECT tablespace_name, status, SUM (bytes) / 1024 / 1024
FROM dba_undo_extents
GROUP BY tablespace_name, status;
TABLESPACE_NAME STATUS Bytes(M)
-------------------- --------- ----------
UNDOTBS1 UNEXPIRED 9.1875
UNDOTBS1 EXPIRED 13.6875
,其中expired 说明是已经过期的数据,也就是15分钟(默认情况)以外的数据,以被覆盖,可以认为是空闲的。
采用UNDO 表空间时,会有一个,
undo_retention 只是指定undo 数据的过期时间,并不是说,undo 中的数据一定会在undo表空间中保存15 分钟,比如说刚一个新事务开始的时候,如果undo 表空间已经被写满,,因此呢,这就又关联回了第一点,当你创建一个自动管理的undo 表空间时,还要注意其空间大小,要尽可能保证undo 表空间有足够的存储空间。
undo_retention 中指定的时间一过,已经提交事务中的数据就立刻无法访问,它只是失效,只要不被别的事务覆盖,它会仍然存在,并可随时被flashback 特性引用。如果你的undo表空间足够大,而数据库又不是那么繁忙,那么其实undo_retention 参数的值并不会影响到你,哪怕你设置成1,只要没有事务去覆盖undo 数据,它就会持续有效。因此呢,这里还是那句话,要注意undo 表空间的大小,保证其有足够的存储空间。
只有在一种情况下,undo 表空间能够确保undo 中的数据在undo_retention 指定时间过期前一定有效,就是为undo ,指定之后,oracle 对于undo 表空间中未过期的undo 数据不会覆盖,例如:
SQL> Alter tablespace undotbs1 retention guarantee;
例如:
SQL> Alter tablespace undotbs1 retention noguarantee;
总结一下:
UNDO 表空间是会被重用的,只有当事务没结束,或开了retention guarantee,或在undo_retention时间内不能被重用。
在undo_retention规定的时间内,数据都是有效的,过期后都会设为无效,状态被改为Expired,这些回滚段将会被看作Free Space。但是只要数据没有被覆盖就可以使用。如果空间已满,新事务的数据会自动,即使在undo_retention的时间内。除非指定Retention Guarantee模式,才能保证在undo_retention内不被覆盖。
SQL> alter system set undo_retention=10800; -- 3个小时
系统已更改。
SQL> create undo tablespace undo datafile ''F:/backup/undo.dbf'' size 1m ;
表空间已创建。
SQL> alter tablespace undo retention guarantee;
表空间已更改。
SQL> alter system set undo_tablespace=undo;
系统已更改。
SQL> create table DBA(id number);
表已创建。
SQL> begin
2 for i in 1 .. 100000 loop
3 insert into dba values(i);
4 commit;
5 end loop;
6 end;
7 /
begin
*
第 1 行出现错误:
ORA-30036: 无法按 8 扩展段 (在还原表空间 ''UNDO'' 中)
ORA-06512: 在 line 3
处理方法有两种,一是添加undo 表空间的数据文件,二是切换UNDO tablespace. 这种情况下多用在undo 表空间已经非常大的情况。
SQL>
表空间已更改。
SQL> begin
2 for i in 1..100000 loop
3 insert into dba values(1);
4 commit;
5 end loop;
6 end;
7 /
PL/SQL 过程已成功完成。
SQL> CREATE UNDO TABLESPACE UNDOTBS2 DATAFILE ''F:/backup/undo03.dbf'' size 100M reuse;
表空间已创建。
SQL> alter system set undo_tablespace=UNDOTBS2 scope=both;
系统已更改。
SQL> alter tablespace UNDO offline;
表空间已更改。
SQL> drop tablespace UNDO including contents AND DATAFILES CASCADE CONSTRAINTS ;
表空间已删除。
Drop undo表空间的时候必须是在未使用的情况下才能进行。如果undo表空间正在使用(例如事务失败,但是还没有恢复成功),那么drop表空间命令将失败。在drop表空间的时候可以使用including contents。
一般Undo 表空间损坏的情况下,数据库都已不能正常打开了。启动时都会报类似如下的错误:
ORA-01157: cannot identify/lock data file 12 - see DBWR trace file
ORA-01110: data file 12: ''/d01/oramtest/proddata/undo01.dbf''
要想解决问题,必须重建UNDO 表空间,但是如果不open, 就不能重建创建undo 表空间。 所以可以先用系统默认的undo 表空间:system rollback segment 来启动数据库,再创建UNDO 表空间。
SQL> create pfile=''F:/initorcl.ora'' from spfile;
文件已创建。
#*.undo_tablespace=''UNDOTBS1''
#*.undo_management=''AUTO''
undo_management=''MANUAL''
rollback_segments=''SYSTEM''
SQL> STARTUP MOUNT pfile=''F:/initorcl.ora'' ;
SQL> ALTER DATABASE DATAFILE ''D:/app/Administrator/oradata/orcl/UNDOTBS01.DBF'' OFFLINE DROP;
SQL> ALTER DATABASE OPEN;
SQL> DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS;
要想一起删除物理文件需要 AND DATAFILES CASCADE CONSTRAINTS ;
如: drop tablespace UNDOTBS1 including contents AND DATAFILES CASCADE CONSTRAINTS ;
SQL> create undo tablespace undotbs1 datafile ''D:/app/Administrator/oradata/orcl/UNDOTBS01.DBF'' size 100M ;
create undo tablespace undotbs1 datafile ''D:/app/Administrator/oradata/orcl/UNDOTBS01.DBF'' size 100M
*
第 1 行出现错误:
ORA-01119: 创建数据库文件 ''D:/app/Administrator/oradata/orcl/UNDOTBS01.DBF''时出错
ORA-27038: 所创建的文件已存在
OSD-04010: 指定了 选项, 但文件已经存在
SQL> create undo tablespace undotbs1 datafile ''D:/app/Administrator/oradata/orcl/UNDOTBS01.DBF'' size 100M reuse;
表空间已创建。
SQL> select name,issys_modifiable from v$parameter where name=''undo_management'' or name=''rollback_segments'';
NAME ISSYS_MOD
-------------------- ---------
rollback_segments FALSE
undo_management FALSE
从上面查询的结果,可以知道修改这2个参数必须重启数据,所以还是shutdown 吧。
SQL> shutdown immediate
*.undo_tablespace=''UNDOTBS1''
*.undo_management=''AUTO''
#undo_management=''MANUAL''
#rollback_segments=''SYSTEM''
SQL> startup pfile=''F:/initorcl.ora'' ;
SQL> create spfile from pfile=''F:/initorcl.ora'';
SQL> shutdown immediate
SQL> startup
一般数据文件损坏的情况也可以采用类似的方法, 先启动到mount, 在将损坏的数据文件offline drop。 在open 数据库,drop 掉损坏的数据文件。 当然这种做法有数据丢失。 能恢复的话,尽量恢复。