Flashback是Oracle自9i就开始提供的一项特性,在9i中利用oracle查询多版本一致的特点,实现从回滚段中读取表一定时间内操作过的数据,可用来进行数据比对,或者修正意外提交造成的错误数据,该项特性也被称为Flashback Query。在10g中Flashback又得到了相当大的增强,利用回收站和闪回区的特性实现快速恢复删除表(Flashback Table)或做数据库时间点恢复(Flashback Database)的功能。
一、Flashback Query
Flashback Query是利用多版本读一致性的特性从UNDO表空间读取操作前的记录数据!
什么是多版本读一致性
Oracle采用了一种非常优秀的设计,通过undo数据来确保写不堵塞读,简单的讲,不同的事务在写数据时,会将数据的前映像写入undo表空间,这样如果同时有其它事务查询该表数据,则可以通过undo表空间中数据的前映像来构造所需的完整记录集,而不需要等待写入的事务提交或回滚。
flashback query有多种方式构建查询记录集(注意,要使用flashback的特性,必须启用自动撤销管理表空间) 记录集的选择范围可以基于时间或基于scn,甚至可以同时查询出记录在undo表空间中不同事务时的前映象。用法与标准查询非常类似,要通过flashback query查询undo中的撤销数据,最简单的方式只需要在标准查询语句的表名后面跟上as of timestamp(基于时间)或as of scn(基于scn)即可。
1、As of timestamp的示例:
先创建一个很简单的表并插入一些记录用于测试:
SQL> create table t_fb_test(v_id,va) as
2 select 1,'a' from dual
3 union
4 select 2,'b' from dual
5 union
6 select 3,'c' from dual
7 union
8 select 4,'d' from dual
9 union
10 select 5,'e' from dual
11 union
12 select 6,'f' from dual;
Table created
SQL> select * from t_fb_test;
V_ID VA
---------- --
1 a
2 b
3 c
4 d
5 e
6 f
删除几条记录并提交:
SQL> delete from t_fb_test where v_id < 4;
SQL> commit;
现在下面我们开始恢复查询:
SQL> select * from t_fb_test as of timestamp sysdate-5/1440;
V_ID VA
---------- --
1 a
2 b
3 c
4 d
5 e
6 f
6 rows selected
哈哈,数据又被我们找回来了(如果报错:ORA-01466:无法读取数据 – 表定义已经更改—这说明你间隔时间估计错误啦,操作过快5分钟之前你还没有建这表拉。)
我们通过增加as of timestamp的语法,就可以到undo表空间中查找到5分钟之前的记录前镜像,使用它我们就可以很轻易的并且迅速的将记录恢复:
SQL> insert into t_fb_test
2 select * from t_fb_test as of timestamp sysdate-3/1440 where v_id < 4;
3 rows inserted
SQL> commit;
as of timestamp的确非常易用,但是在某些情况下,我们建议使用as of scn的方式执行flashback query,比如需要对多个相互有主外键约束的表进行恢复时,如果使用as of timestamp的方式,可能会由于时间点不统一的缘故造成数据选择或插入失败,通过scn方式则能够确保记录的约束一致性。
2、闪回查询之As of scn:
我们通过dbms_flashback.get_system_change_number函数来获取oracle当前的scn,之后再执行数据的修改操作。
SQL> select dbms_flashback.get_system_change_number from dual;
GET_SYSTEM_CHANGE_NUMBER
------------------------
14229608
删除数据:
SQL> delete from t_fb_test where v_id > 4;
2 rows deleted
SQL> commit;
闪回查询:
SQL> select * from t_fb_test as of scn 14229608;
V_ID VA
---------- --
1 a
2 b
3 c
4 d
5 e
6 f
6 rows selected
然后我们可以用insert语句借助 as of scn查询结果将数据恢复回来。
事实上,Oracle在内部都是使用scn,即使你指定的是as of timestamp,oracle也会将其转换成scn,系统时间标记与scn之间存在一张表,即SYS下的SMON_SCN_TIME
每隔5分钟,系统产生一次系统时间标记与scn的匹配并存入sys.smon_scn_time表,该表中记录了最近1440个系统时间标记与scn的匹配记录,由于该表只维护了最近的1440条记录,因此如果使用as of timestamp的方式则只能flashback最近5天内的数据(假设系统是在持续不断运行并无中断或关机重启之类操作的话)。注意理解系统时间标记与scn的每5分钟匹配一次这句话,举个例子,比如scn:339988,339989分别匹配08-05-30 13:52:00和2008-13:57:00,则当你通过as of timestamp查询08-05-30 13:52:00或08-05-30 13:56:59这段时间点内的时间时,oracle都会将其匹配为scn:339988到undo表空间中查找,也就说在这个时间内,不管你指定的时间点是什么,查询返回的都将是08-05-30 13:52:00这个时刻的数据。
当然,具体的情况,我想你亲自执行一下select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss') from sys.smon_scn_time,会理解的更深刻一些。
关于我SCN与timestamp/date时间之间的转换,以及SCN实现机制原理可以看我另一篇博文《Oracle SCN 实现机制总结 》有详细介绍: