在Oracle的备份恢复过程中,需要注意数据文件的unrecoverable,不适当的操作很容易造成恢复后有大量的坏块。在视图v$datafile中,UNRECOVERABLE_CHANGE#和UNRECOVERABLE_TIME分别表示数据文件最后一个unrecoverable操作的change#和时间。unrecoverable通常就是指不记录日志的操作(nologging),这样当用一个旧的数据文件还原后,用日志进行恢复时,由于日志文件没有记录unrecoverable的操作时的日志,导致那些操作的数据块为逻辑坏块(实际上在日志文件中为这样的操作产生了一些重做日志项,在恢复时,根据这些重做日志项,直接将相应的数据块标记为坏块)。常见的以下几种情况:
1. 非归档模式下的create table as 操作和直接路径插入(如加了append hint的insert语句和直接路径装载)
2. 归档模式下的create table xxx nologging(即创建表时为表指定了nologging)和nologging表的直接路径插入。
在数据库(或表空间)为force logging时,任何操作都会记录日志。不会有unrecoverable操作。
下面先做个实验(数据库版本为9.2.0.1)来看看这两列:
数据库当前处于非归档模式;
SQL> select name,checkpoint_time,unrecoverable_time from v$datafile where file#=10;
NAME CHECKPOINT_TIME UNRECOVERABLE_TIME
---------------------------------------- ------------------- -------------------
D:\ORACLE\ORADATA\XJ\TEST01.DBF 2008-09-23 09:28:22SQL> create table t tablespace test nologging as select * from dba_objects where rownum< =10; 表已创建。 SQL> select name,checkpoint_time,unrecoverable_time from v$datafile where file#=10;
NAME CHECKPOINT_TIME UNRECOVERABLE_TIME
---------------------------------------- ------------------- -------------------
D:\ORACLE\ORADATA\XJ\TEST01.DBF 2008-09-23 09:28:22
可以看到,unrecoverable_time为空。想一想就可以理解,unrecoverable操作都是将数据直接写入了数据文件,没有经过SGA的缓存,非归档模式下的物理备份都是一致的冷备份,不需要日志来进行恢复,因此对于非归档模式下并不存在unrecoverable操作。unrecoverable只是针对归档模式的。下面将数据库置为归档模式后,重复上述过程,进行验证:
SQL> create table t tablespace test nologging as select * from dba_objects where rownum< =10; 表已创建。 SQL> select name,checkpoint_time,unrecoverable_time,unrecoverable_change# from v$datafile where file#=10;
NAME CHECKPOINT_TIME UNRECOVERABLE_TIME UNRECOVERABLE_CHANGE#
---------------------------------------- ------------------- ------------------- ---------------------
D:\ORACLE\ORADATA\XJ\TEST01.DBF 2008-09-23 09:45:03 2008-09-23 09:45:41 1298047可以看到,v$datafile视图中unrecoverable_time和unrecoverable_change#已经有了值。
下面来看看unrecoverable_time是最后一次unrecoverable操作的开始时间还是结束时间?
创建一个具有延时功能的函数:create or replace function f_cdate return date
as
begin
dbms_lock.sleep(10);
return sysdate;
end;SQL> create table t (d date) nologging tablespace test;
表已创建。
SQL> begin
2 dbms_output.put_line('start test:'||sysdate);
3 insert /*+ append */ into t select f_cdate from dba_objects where rownum< =10; 4 dbms_output.put_line('after insert:'||sysdate); 5 dbms_lock.sleep(60); 6 commit; 7 dbms_output.put_line('end test:'||sysdate); 8 end; 9 / start test:2008-09-23 10:31:50 after insert:2008-09-23 10:33:33 end test:2008-09-23 10:34:34 PL/SQL 过程已成功完成。 SQL> select name,checkpoint_time,unrecoverable_time,unrecoverable_change# from v$datafile where file#=10;NAME CHECKPOINT_TIME UNRECOVERABLE_TIME UNRECOVERABLE_CHANGE#
---------------------------------------- ------------------- ------------------- ---------------------
D:\ORACLE\ORADATA\XJ\TEST01.DBF 2008-09-23 09:45:03 2008-09-23 10:33:33 1299032
SQL> begin
2 dbms_output.put_line('start test:'||sysdate);
3 insert /*+ append */ into t select f_cdate from dba_objects where rownum< =10; 4 dbms_output.put_line('after insert:'||sysdate); 5 dbms_lock.sleep(60); 6 rollback; 7 dbms_output.put_line('end test:'||sysdate); 8 end; 9 / start test:2008-09-23 10:37:59 after insert:2008-09-23 10:39:42 end test:2008-09-23 10:40:43 PL/SQL 过程已成功完成。 SQL> select name,checkpoint_time,unrecoverable_time,unrecoverable_change# from v$datafile where file#=10;NAME CHECKPOINT_TIME UNRECOVERABLE_TIME UNRECOVERABLE_CHANGE#
---------------------------------------- ------------------- ------------------- ---------------------
D:\ORACLE\ORADATA\XJ\TEST01.DBF 2008-09-23 09:45:03 2008-09-23 10:39:42 1299157可以看到unrecoverable_time为unrecoverable操作完成的那个时间,不管事务是否提交。
对于数据库备份后的恢复,需要注意查询v$datafile视图中关于unrecoverable操作时间,如果unrecoverable操作时间在数据文件备份之后(更精确的比较是通过change#,比较文件的checkpoint_change#和unrecoverable_change#),则恢复会产生坏块。
建议重要的数据库,将数据库置为force logging(当然数据库应当是归档模式),避免无意的产生了unrecoverable操作。或者在做了unrecoverable操作之后立即进行数据文件的备份。
PS:关于不产生日志的操作,请参见metalink NOTE:269274.1 CHECK FOR LOGGING/NOLOGGING ON DB OBJECT(S)
no comment untill now