闪回技术(Flashback),是Oracle 11g数据库提供的7个能使数据库整体或局部回到“过去”的闪回功能的总称,主要用于对抗人为错误。在这些功能中,有的不会修改现有的数据而只是展示以前的数据,即能够观察过去;有的可以将数据修改为以前的值,即真正地回到过去。
闪回技术的7种功能为 —— 闪回查询、闪回数据归档、闪回事务查询、闪回事务、闪回表、闪回删除和闪回数据库。
单位为秒,该参数是一种建议机制,表示任何修改所产生的撤销数据应该在发起修改的事务提交之后再保留多长时间。默认建议是900s
SQL> show parameter undo_retention
若能够自动增长,则undo_retention参数的建议能够被最大限度地采纳。
select autoextensible from dba_data_files where tablespace_name=(select value from v$parameter where name='undo_tablespace');
必须注意,若自动增长且undo_retention设置太高,UNDO表空间可能很大
GARANTEE使原本为“建议”的undo_retention变为强制的“规定”。默认为NOGARANTEE。
select retention from dba_tablespaces where tablespace_name='UNDOTBS1';
用“alter tablespace”命令可修改UNDO表空间的RETENTION属性:
SQL> alter tablespace undotbs1 retention guarantee;
Tablespace altered.
若UNDO表空间能够自动增长再配合高的不合理的undo_retention设置,现在再加上GUARANTEE设置,在这种情况下只能说请管理员自重了,准备迎接巨无霸UNDO表空间吧。
显然事务量越大产生新的撤销数据的速率就越高,面对庞大的事务量管理员在设置以上3要素时必须做出艰难的决定:想要确保UNDO表空间尽量小撤销数据提交后肯定留不了多久,极端情况是接近900s;若要确保撤销数据提交后再留得久一些,UNDO表空间必然变得很大。其中利弊只能由管理员自己权衡了。
切记以上影响闪回查询时间窗口的4因素,闪回事务查询、闪回表的时间窗口同样受其影响。总而言之,闪回查询时间窗口可以有多大,最终取决于数据库能容忍一个多大的UNDO表空间,即用空间换“过去的时间”。
二、 闪回查询(Flashback Query)
以表为单位查询其过去的数据称为闪回查询
可以细分为两种:
1. 闪回时间点查询:利用select命令的“as of”子句与PL/SQL包dbms_flashback在过去的一个时间点上的查询
2. 闪回版本查询:利用select命令的“versions between”子句在过去的一段时间范围内的查询
闪回查询能够在撤销段内搜索撤销数据(“旧”数据),数据库能够保留多少撤销数据决定了闪回查询的时间窗口的大小
通过下面几个例子很容易了解“as of”子句使用方法及其功能。
示例1:查询hr.employees在2011年10月10日上午6点40分37秒时所有的行:
SQL> select * from hr.employees as of timestamp to_timestamp('2011-10-10 06:40:37','YYYY-MM-DD HH24:MI:SS');
示例2:查询100号员工5分钟前的薪水:
SQL> select salary from hr.employees as of timestamp (systimestamp - interval '5' minute) where employee_id=100;
示例3:查询100号员工在SCN为1243223时的工种(JOB_ID字段):
SQL> select job_id from hr.employees as of scn 1243223 where employee_id=100;
示例4:将10分钟前的hr.employees表与1小时前的hr.departments表以department_id为条件进行关联(Join):
SQL> select e.last_name, d.department_name
from hr.employees as of timestamp(systimestamp - interval '10' minute) e,hr.departments as of timestamp(systimestamp - interval '1' hour) d
where e.department_id = d.department_id
示例5:将100号员工的EMAIL字段修改为15分钟前的值:
SQL> update hr.employees set email=(select email from hr.employees as of timestamp (systimestamp - interval '15' minute) where employee_id=100)
where employee_id=100
示例6:闪回PACKAGE
首先查询对象的 obj#号是多少
SELECT obj# FROM obj$ AS OF TIMESTAMP TO_TIMESTAMP('2011-09-08 15:25:00', 'YYYY-MMDD HH24:MI:SS') WHERE NAME = 'TEST_PACKAGE';
OBJ#
76389
76390
有两个值,一个是包头,一个是包体
然后再用如下的 sql 查询正确值时间点的数据
SELECT source FROM source$ AS OF TIMESTAMP TO_TIMESTAMP('2011-09-08 15:25:00', 'YYYYMM-DD HH24:MI:SS') where obj# = 76390;
SELECT source FROM source$ AS OF TIMESTAMP TO_TIMESTAMP('2011-09-08 15:25:00', 'YYYYMM-DD HH24:MI:SS') where obj# = 76389;
通过如上两个sql 结果内容就可以恢复了
闪回时间点查询的另一种方法是首先用PL/SQL包dbms_flashback的enable_at_time或enable_at_scn存储过程锁定一个会话级别的闪回时间目标,即进入闪回模式,随后的查询命令就可以省略“as of”,但也能达到使用“as of”的闪回效果,直到调用dbms_flashback. disable存储过程关闭闪回模式为止。
比如,将闪回模式会话定格在15分钟前:
SQL> exec dbms_flashback.enable_at_time(systimestamp - interval '15' minute);
PL/SQL procedure successfully completed.
现在,虽然没有“as of”子句,以下查询命令的含义就是查看15分钟前的hr.employees表:
SQL> select * from hr.employees;
需要注意此时若访问SYSDATE、SYSTIMESTAMP等日期函数,它们的返回值还是正常的当前的值,而不是静止在15分钟以前。另外,处于闪回会话模式时,执行dml和ddl将报错,还有,SYS用户不能调用enable_at_time和enable_at_scn:
SQL> exec dbms_flashback.enable_at_time(systimestamp - interval '15' minute); BEGIN dbms_flashback.enable_at_time(systimestamp - interval '15' minute); END; *
ERROR at line 1:
ORA-08185: Flashback not supported for user SYS
ORA-06512: at "SYS.DBMS_FLASHBACK", line 3
ORA-06512: at line 1
在回到过去对所有感兴趣的表查询一番后,再调用disable存储过程关闭闪回会话模式回到正常状态:
SQL> exec dbms_flashback.disable
PL/SQL procedure successfully completed.
闪回版本查询用于查询一段时间范围内表的数据,通过只使用一条查询命令就能返回该时间窗口内的不同时间点上的数据,其语法是在表名之后加“versions between”子句。
比如,首先通过3个事务将200号员工的薪水进行修改。其值原先是4400,然后是700000和5000,最后为1:
对200号员工执行闪回版本查询的结果将返回多个200号员工:
select employee_id,salary from hr.employees versions between timestamp (systimestamp - interval '10' minute) and maxvalue where employee_id=200;
EMPLOYEE_ID SALARY
----------- ----------
200 1
200 5000
200 700000
200 4400
通过“versions between”,笔者指定的时间窗口是10分钟前到当前时间(第4行中以maxvalue表示),发现在此区间内200号员工的SALARY有过4个值,说明共有3个事务对其进行过修改并提交。
为了能看清这些事务的先后顺序,可以在查询列表中使用闪回版本查询特有的伪字段,留意以下命令的第2行:
SQL> select versions_xid,versions_startscn,versions_endscn,employee_id,salary
from hr.employees versions between timestamp (systimestamp - interval '15' minute) and maxvalue
where employee_id=200
order by 2 nulls first;
其中VERSIONS_XID表示事务号,VERSIONS_STARTSCN和VERSIONS_ENDSCN分别是事务开始时的SCN和修改该行的下一个事务开始时的SCN,首尾衔接这两个字段的SCN号很容易得到真实的修改顺序:4400,700000,5000,最后变为1。
所有能够在闪回版本查询中使用的伪字段有VERSIONS_XID、VERSIONS_STARTSCN、VERSIONS_ENDSCN、VERSIONS_STARTTIME和VERSIONS_ENDTIME。
三、 闪回数据归档(Flashback Data Archive)
闪回查询对撤销数据及参数undo_retention的依赖注定了它们在大事务量的情况下闪回时间窗口将会很小,想要查询数月之前的“旧”数据绝对不可能,但在闪回数据归档面前这并不是不可能的。
闪回数据归档的工作原理是将原本只能保存在UNDO表空间的撤销数据额外的以一种历史表的形式保存在指定的普通表空间中,并且不像undo_retention参数那样是个影响整个数据库的设置。闪回数据归档可以只为特定的表服务,这样就可以长时间地保存感兴趣的“旧”数据了。
比如,在USERS表空间中创建一个能够将“旧”数据保存1年的数据归档,取名为“FDA1”,操作者必须拥有“flashback archive administer”系统权限:
SQL> create flashback archive fda1 tablespace users retention 1 year;
Flashback archive created.
或者创建一个默认的闪回数据归档,取名为“fda_default”,操作者必须拥有SYSDBA权限:
SQL> create flashback archive default fda_default tablespace users retention 1 year;
Flashback archive created.
有了归档,就可以使用“flashback archive”子句在特定的表上启用闪回数据归档功能了。比如,让hr.employees使用fda1,从此该表的修改历史将保留1年:
SQL> alter table hr.employees flashback archive fda1;
Table altered.
若执行以上命令的是个普通账号,比如HR用户,那么其在执行命令前必须被授予“flashback archive”对象权限,比如:
SQL> grant flashback archive on fda1 to hr;
Grant succeeded.
若有默认的闪回数据归档,则启用时不必给出其名称。比如,让hr.departments使用默认的FDA,从此该表的修改历史也将保留1年:
SQL> create table oe.inventory(id number,product_id number,supplier_id number) flashback archive fda1;
Table created.
使用“no flashback archive”子句可以关闭特定表上的闪回数据归档功能。执行该命令需要“flashback archive administer”系统权限:
SQL> alter table oe.inventory no flashback archive;
Table altered.
启用闪回数据归档之后大大扩展了闪回查询的时间窗口,比如在启用归档功能至少7个月之后再查看hr.employees表7个月前的内容:
SQL> select * from hr.employees as of timestamp (systimestamp - interval '7' month);
以hr.employees基表为例,使用以下查询能够一睹闪回归档的主要信息:
SQL> select a.flashback_archive_name fda_name,a.retention_in_days days,ts.tablespace_name ts,ts.quota_in_mb,t.archive_table_name
From dba_flashback_archive a,dba_flashback_archive_ts ts, dba_flashback_archive_tables t
Where a.flashback_archive_name = ts.flashback_archive_name and a.flashback_archive_name = t.flashback_archive_name and t.owner_name = 'HR' and t.table_name = 'EMPLOYEES';
其中ARCHIVE_TABLE_NAME字段的值就是归档中历史表的名字——SYS_FBA_HIST_73953,该表不能直接查询,更不用提其他操作了。
此外结果中还显示了配额的大小(QUOTA_IN_MB)为空,即没有配额限制。管理员在创建闪回归档时实际上可以为其设置能够占用的磁盘空间上限,即所谓的配额。
比如创建归档fda2时限制其空间限制为40GB:
SQL> create flashback archive fda2 tablespace users quota 40G retention 2 year;
Flashback archive created.
另外,闪回数据归档中的历史数据当然可以被手工清除。比如清除归档fda中一个月之前的数据:
SQL> alter flashback archive fda purge before timestamp (systimestamp - interval '1' month);
Flashback archive altered.
或全部清除:
SQL> alter flashback archive fda purge all;
Flashback archive altered.
启用了闪回数据归档功能的表依然支持绝大多数的ddl命令。但在执行少数ddl命令时会遭遇“ORA-55610: Invalid DDL statement on history-tracked table”错误,比如“alter table … shrink space”、“alter table … move”、“alter table … exchange partition”等。
四、 闪回事务查询
闪回事务查询有别于闪回查询的特点有以下3个:
(1)其正常工作不但需要利用撤销数据,还需要事先启用最小补充日志。
(2)返回的结果不是以前的“旧”数据,而是能够将当前数据修改为以前的样子的撤销SQL(Undo SQL)语句。
(3)都在flashback_transaction_query表上查询,而不是在各个表上通过“as of”或“versions between”子句查询。
首先打开最小补充日志:
SQL> alter database add supplemental log data;
从此以后,只要在闪回查询的查询窗口内,管理员就可以通过flashback_transaction_query表获得相关事务的撤销SQL。
下面列举一个典型的闪回事务查询的使用方法。
场景:用户在一个事务中分别使用insert和update命令修改了hr.departments和hr.employees表,命令细节如下所示:
SQL> insert into hr.departments(department_id,department_name,manager_id,location_id) values (999,'SETI',100,1700);
SQL> update hr.employees set department_id=999 where employee_id=200;
SQL> commit;
该事务创建了一个新的999号部门,并且将200号员工指派入该新部门。可惜这个事务是人为错误!如何利用闪回事务查询恢复原始状态?
首先通过闪回版本查询获得该事务的XID,比如从错误的999号部门入手:
SQL> select versions_xid,versions_startscn,department_id,department_name
from hr.departments versions between timestamp minvalue and maxvalue
where department_id=999
order by 2 nulls first;
然后使用结果中的事务号090010002B030000查询flashback_transaction_query表以获得撤销SQL:
SQL> select undo_sql from flashback_transaction_query
where xid='090010002B030000';
UNDO_SQL
--------------------------------------------------
update "HR"."EMPLOYEES" set "DEPARTMENT_ID" = '10' where ROWID = 'AAAR5pAAFAAAADLAAC';
delete from "HR"."DEPARTMENTS" where ROWID = 'AAAR5kAAFAAAACtAAA';
2 rows selected.
结果得到了两句dml命令,如果遵循给出的ROWID不难发现撤销SQL试图将hr.employees表中200号员工的部门从999修改为10:
并且试图删除999号部门:
闪回事务查询可以将同一事务的所有撤销SQL列出,这是闪回查询做不到的,如有必要,管理员还能够执行对应一个事务的部分撤销SQL以一种破坏事务原子性的方式恢复一部分数据,如此行事正确与否完全取决于应用的逻辑。
最后,因为ddl命令的撤销SQL包括对数据字典表的DML操作,并且人为地直接修改数据字典表是非常危险的,况且某些DDL操作不仅仅是对数据字典的DML操作,它们还涉及撤销SQL无法影响到的领域,所以不要指望通过直接执行撤销SQL恢复错误的ddl命令造成的影响。
五、 闪回事务(Flashback Transaction)
到目前为止,介绍的所有功能均不会直接将数据恢复为“以前”的样子。闪回查询只是查看,闪回数据归档只是延伸了闪回查询的时间窗口,闪回事务查询虽然提供了撤销SQL,但是否执行及如何执行还需要管理员进一步手动操作。
若是管理员决定撤销某个或某些事务,Oracle提供一个专门用来撤销事务的工具——闪回事务。
闪回事务又名撤销事务(Backout Transaction),能够撤销一个或多个事务的修改,其功能由一个名为DBMS_FLASHBACK.TRANSACTION_BACKOUT的存储过程实现。该存储过程的工作原理是自动分析重做日志,挖掘出变更前的值用以构建撤销SQL(Undo SQL),然后执行撤销SQL最后达到撤销事务的目的。
为了该功能可以正常使用,至少需要事先启用主键补充日志。另外,为了能够跟踪外键依赖还需要启用外键补充日志。
在继续讨论此功能前,首先应了解一个概念:事务的依赖性。比如,两个事务TX1和TX2,若符合以下3个条件的任意一个就可以认为TX2依赖TX1:
(1)WAW依赖(Write After Write),即在TX1修改了表的某行之后,TX2又修改了同一行。
(2)主键依赖,即在一张拥有主键的表中TX1首先删除了一行,之后TX2又插入了具有相同主键值的另一行。
(3)外建依赖,即由于TX1的修改(insert或update)而产生了新的可被外键参考的字段值,之后TX2修改(insert或update)外键字段时利用了TX1所产生的字段值。
了解事务依赖性有助于解决在撤销事务时遇到的矛盾,以主键依赖为例,试想若直接将事务TX1撤销并且不理会事务TX2,岂不是会出现主键值重复的行!
TRANSACTION_BACKOUT存储过程的OPTIONS参数就是为了解决事务依赖性问题而存在的,在该参数上管理员可以使用4种撤销事务的方案,假设被撤销的事务是TX1,若其具有依赖事务,则称为TX2:
(1)NOCASCADE,TX1不可以被任何其他事务依赖(即TX2不存在),否则撤销操作报错。
(2)CASCADE,将TX1连同TX2一起撤销。
(3)NOCASCADE_FORCE,忽略TX2,直接执行TX1的撤销SQL将TX1撤销,如果没有约束上的冲突,操作将成功,否则约束报错导致撤销操作失败。
(4)NONCONFILICT_ONLY,在不影响TX2的前提下,撤销TX1的修改。与NOCASCADE_FORCE的不同点在于会首先过滤一下TX1的撤销SQL,确保它们不会作用在TX2修改的行上。
使用DBMS_FLASHBACK.BACKOUT_TRANSACTION的步骤如下:
(1)将需要撤销的事务的事务号或事务名载入对应的VARRAY集合变量。
SQL> select distinct xid,commit_scn
from flashback_transaction_query
where table_owner='HR' and table_name='EMPLOYEES' and commit_timestamp > systimestamp - interval '15' minute
order by commit_scn;
XID COMMIT_SCN
---------------- ----------
0A00160094020000 1277129
0900070068030000 1277301
(2)以NOCASCADE方式调用BACKOUT_TRANSACTION。如果报错,再从另外3种方式中选择一个调用BACKOUT_TRANSACTION。
SQL> declare
xids sys.xid_array;
begin
xids := sys.xid_array('0A00160094020000');
dbms_flashback.transaction_backout(1,xids,options=>dbms_flashback.nocascade);
end;
/
第5行中存储过程的第二个参数是一个容纳事务号的VARRAY集合变量,第一个参数表示VARRAY内事务号的数量,本例中只有一个事务需要撤销,所以等于1。
(3)查看闪回事务操作的报告。
(4)最后决定提交或回滚。
六、 闪回表(Flashback Table)
本节介绍的闪回表“flashback table”命令能够以表为单位(而不是像闪回事务那样以事务为单位)将数据恢复为“以前”的样子。
因为闪回表也是利用UNDO表空间的撤销数据,所以到底能将表闪回到多久之前同样受到闪回查询4因素的影响,另外切记闪回数据归档不能为闪回表服务。
闪回表的语法十分简单,用以下几个例子便可以说明。
示例1:将hr.employees闪回到10分钟之前:
SQL> flashback table hr.employees to timestamp (systimestamp - interval '10' minute);
Flashback complete.
示例2:将hr.employees闪回到SCN为1080381的时候:
SQL> flashback table hr.employees to scn 1080381;
Flashback complete.
示例3:将hr.employees和hr.departments两张表同时闪回到SCN为1080381的时候(有外键参考关系的表的确可能需要一起闪回):
SQL> flashback table hr.employees,hr.departments to scn 1080381;
Flashback complete.
使用闪回表的注意事项如下。
(1)被闪回的表必须启用行移动功能,比如:
SQL> alter table hr.employees enable row movement;
Table altered.
(2)“FLASHBACK TABLE”命令的执行者必须有“FLASHBACK ANY TABLE”系统权限或者在被闪回的表上具有“FLASHBACK”对象权限。
(3)“FLASHBACK TABLE”属于ddl命令,所以自带提交(Commit)功能。
(4)SYS用户的任何表无法使用此功能。
七、 闪回删表(Flashback Drop)
闪回删表指的是撤销“DROP TABLE”的效果(需要启用回收站),命令主要结构为“FLASHBACK TABLE … TO BEFORE DROP”。
比如,创建一张带数据的新表EMP:
SQL> create table emp tablespace users as select * from hr.employees;
Table created.
删除EMP:
SQL> drop table emp;
Table dropped.
救回EMP:
SQL> flashback table emp to before drop;
Flashback complete.
SQL> select count(*) from emp;
COUNT(*)
----------
107
该功能的工作原理是:当“drop table”命令执行时,表及其索引并没有被真正删除,其所占空间(称为段)只是分配给了另一种数据库对象:回收站对象,并且这种所谓的分配使数据和数据块没有发生任何移动,还是待在原来的数据文件及表空间中。
回收站对象的信息可以通过查询dba_recyclebin视图获得,普通用户可以使用快捷方式“show recyclebin”命令查看自己的回收站:
SQL> show recyclebin
回收站对象本身也可以被查询:
SQL> select count(*) from "BIN$r4C+sJfzPq7gQAsLDAsoBQ==$0";
COUNT(*)
----------
107
将回收站对象取出,并命名一个新名字:
SQL> flashback table emp to before drop rename to empold;
Flashback complete.
如果表名重复,在闪回时遵循后入先出原则,留意“show recyclebin”命令显示的“DROP TIME”字段:
或者在闪回时指明被恢复的回收站对象:
SQL> flashback table "BIN$r4D3SgQXjj7gQAsLDAsxdw==$0" to before drop;
Flashback complete.
诚然,回收站对象毕竟是一种弱存在,Oracle没有义务永远保留被删除的表的数据,表空间在自动增长的压力下会按照先入先出的规则将回收站对象的区(数据块的集合)分配给需要空间的段,在将回收站对象耗尽之前数据文件是不会自动增长的,反之,若数据文件自动增长了,那么在其内的所有回收站对象已经全部失效了。
以下查询可以确认有哪些回收站对象因为原本属于自身的区(数据块的集合)被别的段占用已经不能回到被DROP之前了:
SQL> select owner,object_name,original_name
from dba_recyclebin where can_undrop='NO';
no rows selected
若无意使用回收站服务,可以采用purge命令或子句清空或跳过回收站。比如,删除EMP表并且不产生回收站对象:
SQL> drop table emp purge;
Table dropped.
删除一个特定的回收站对象:
SQL> purge table "BIN$r4D3SgQmjj7gQAsLDAsxdw==$0";
Table purged.
删除当前用户的回收站中的所有对象:
SQL> purge user_recyclebin;
Recyclebin purged.
删除数据库中所有的回收站中的所有对象:
SQL> purge dba_recyclebin;
DBA Recyclebin purged.
若要完全禁用回收站功能,可将静态参数recyclebin改为“off”后重启实例:
SQL> alter system set recyclebin='off' scope=spfile;
System altered.
SQL> startup force;
八、 闪回数据库
闪回数据库的命令是“flashback database to ”,可以是SCN、时间或还原点,顾名思义,就是将整个数据库回退到指定的一个时间点,实际上是数据库不完全恢复的另一种方式。真正的不完全恢复需要消耗的时间与数据库的大小有密切联系,数据库越庞大,需要的时间就越多,对于大型数据库来说,哪怕是只为了回到30秒之前,消耗的时间也是惊人的。
闪回数据库技术改变了这个窘境,其处理问题方式可以着重于如何将相对较短的时间内发生的变更去除,而不是如何还原足够旧的备份(这已经很花时间了),再利用归档日志前滚至指定时间。闪回的“闪”字用在这里显得十分贴切。
闪回数据库需要使用两种日志:闪回日志和归档日志。其中归档日志已为大家所知,而闪回日志就像是归档日志的反作用力,闪回日志的记载正好与归档日志的记载相反。比如,逻辑上归档日志记录insert命令的重做记录,闪回日志就记录delete命令的重做记录(当然实际上没那么简单)。在发起闪回操作时,只要根据写入闪回日志的相反顺序,即后写先读的顺序,将闪回记录从闪回日志读出并执行其记录的变更就能够将数据库在时间轴上倒推。
闪回日志的保存路径一定是快速恢复区的子目录,保存的期限则由参数db_flashback_retention_target控制(分钟),凡是超出保存期限的闪回日志将会在快速恢复区空间紧张的时候被自动删除。比如,指定数据库保留两天的闪回日志和归档日志:
SQL> alter system set db_flashback_retention_target=2880;
System altered.
使用v$database.FLASHBACK_ON可以查看闪回日志是否已启用,现在是“NO”,表示尚未启用:
SQL> select flashback_on from v$database; FLASHBACK_ON
------------------
NO
在确保启用了归档模式之后,使用以下命令可以启用闪回日志,即闪回数据库功能:
SQL> alter database flashback on;
Database altered.
在快速恢复区的flashback子目录下将会出现扩展名为.flb的文件,它们就是闪回日志。
SQL> select flashback_on from v$database;
FLASHBACK_ON
------------------
YES
闪回数据库命令的语法很简单:在进入MOUNT状态后执行“flashback database to scn …”或“flashback database to timestamp …”。
一次闪回数据库操作可能由两种方式进行。
比如,令当前时间点为TC,数据库闪回的目标时间点为T1(TC大于T1),使用的命令为“flashback database to timestamp ”,该命令会自动选择以下两种方式的其中一个进行闪回操作。
方式一:
(1)第一阶段:利用闪回日志将数据库从TC“倒推”至较T1更旧的某一时刻T2。
(2)第二阶段:利用归档日志将数据库从T2“前滚”至T1。
方式二:
(1)第一阶段:确定一个比T1更旧的某一时刻T2。
(2)第二阶段:对于闪回日志根本无法恢复的对象或数据,令当初此类对象第一次产生的时间为T3,首先利用T3到T2的归档日志将其重新产生并恢复。
(3)第三阶段:利用闪回日志将数据库从TC“倒推”至T2。
(4)第四阶段:利用归档日志将数据库从T2“前滚”至T1(途中经过T2)。
究竟采用哪种方式执行取决于目标时间点T1与当前时间点TC之间执行过什么命令,如果是在闪回日志中有对应反向操作的命令(如insert、update、delete)就采用方式一;如果在闪回日志中找不到对应反向操作的命令(比如:truncate命令)则采用方式二。方式二较方式一可能会索要更多的归档日志才可以完成闪回。
若有任何对象发生过截断操作(truncate table …),那么方式二中的T3就是被截断的表当初创建的时刻,这意味着整个闪回操作需要从T3至T1的所有的归档日志,否则闪回数据库不可能成功。这样,可能会发生这样的问题:即使只是在10秒前错误地截断了一张表,现需要回到10秒之前,但是闪回数据库时“flashback database”命令向管理员索要一年前的归档日志!
悲观情绪不必过度蔓延,如果T1和TC之间只是发生过类似update那样的DML,若是想回到10秒前,那么会采用方式一,差不多只是需要10秒的闪回日志和归档日志,闪回会很快,这也是闪回的真谛。
无论哪种方式,都可能遇到归档日志不充分的问题,报错信息类似如下所示:
SQL> flashback database to scn 1036988; flashback database to scn 1036988 *
ERROR at line 1:
ORA-38754: FLASHBACK DATABASE not started; required redo log is not available ORA-38762: redo logs needed for SCN 1036814 to SCN 1036988
ORA-38761: redo log sequence 19 in thread 1, incarnation 2 could not be accessed
也可能遇到闪回日志不够的问题,报错信息如下所示:
SQL> flashback database to scn 1036988; flashback database to scn 1036988 *
ERROR at line 1:
ORA-38729: Not enough flashback database log data to do FLASHBACK.
现在讨论一下具体的闪回步骤应该如何操作。在发起闪回操作前,推荐查看一下v$flashback_database_log视图,检查最远可以回到哪里:
select oldest_flashback_scn,to_char(oldest_flashback_time,'YYYY-MM-DD HH24:MI:SS') from v$flashback_database_log;
OLDEST_FLASHBACK_SCN TO_CHAR(OLDEST_FLAS
-------------------- -------------------
1041426 2011-10-17 02:57:34
进入MOUNT状态发起闪回操作后,管理员可以反复地以任何顺序执行这3个命令:“flashback database to …”、“recover database”和“alter database open read only”。
比如,先进入数据库的MOUNT状态:
SQL> startup force mount;
回到SCN号1041440:
SQL> flashback database to scn 1041440;
Flashback complete.
以只读形式打开数据库,这样就可以查看SCN在1041440时数据库中的所有数据,以便判断闪回操作是否达到目的:
SQL> alter database open read only;
Database altered.
如此循环,直到获得满意的结果为止。
如果是从库,并且有足够的归档,可以直接开启日志应用
alter database recover managed standby database using current logfile disconnect from session parallel 4;
如果归档不够,可以尝试闪回到最近有归档保留的时候再开启日志应用,或者从主库拷贝归档过来再进行注册(比较麻烦)
如果是主库,最后以resetlogs方式打开数据库,效果和不完全恢复一模一样:
SQL> startup force mount;
SQL> alter database open resetlogs;
Database altered.
参考:《临危不惧Oracle11g数据库恢复技术》