本文主要介绍利用UNDO表空间的闪回技术,主要包括:闪回表,闪回版本查询,闪回事务查询,闪回查询。这些闪回技术实现从回滚段中读取表中一定时间内操作过的数据,可用来进行数据比对,或者修正意外提交造成的错误数据。由于利用的是UNDO表空间里记录的数据被改变前的值,因此数据在UNDO空间中保留多久就尤为重要,其中与之关系最紧密的是 UNDO_RETENTION参数。
关于UNDO_RETENTIONUNDO_RETENTION 通常默认是900 秒,也就是15 分钟。值得注意是,undo_retention 只是指定undo 数据的过期时间,并不是说,undo 中的数据一定会在undo表空间中保存15 分钟,比如说刚一个新事务开始的时候,如果undo 表空间已经被写满,则新事务的数据会自动覆盖已提交事务的数据,而不管这些数据是否已过期。因此,当你创建一个自动管理的undo 表空间时,还要注意其空间大小,要尽可能保证undo 表空间有足够的存储空间。同时还要注意,也并不是说,undo_retention 中指定的时间一过,已经提交事务中的数据就立刻无法访问,它只是失效,只要不被别的事务覆盖,它会仍然存在,并可随时被flashback 特性引用。如果你的undo表空间足够大,而数据库又不是那么繁忙,那么其undo_retention 参数的值并不会影响到你,哪怕你设置成1,只要没有事务去覆盖undo 数据,它就会持续有效。因此呢,这里还是那句话,要注意undo 表空间的大小,保证其有足够的存储空间。因此如果闪回表时所需要的UNDO数据,由于保留的时间超过了UNDO_RETENTION的所指定的值,从而导致该UNDO数据被其他事务覆盖的话,那么就不能闪回到指定时间了。 表空间上指定了retention guarantee选项使UNDO数据在一定时间内不被覆盖。修改UNDO_RETETION的值命令如下:SQL> alter system set undo_retention=600 scope=both;启用undo guaranteeSQL> alter tablespace undotbs1 retention guarantee;禁用undo guaranteeSQL> alter tablespace undotbs1 retention noguarantee;实验环境SQL> create table flash_test(id int,name varchar2(10));Table created.SQL> declare 2 v_int int :=1; 3 begin 4 for v_int in 1..10 loop 5 insert into flash_test values(v_int,'oracle'); 6 end loop; 7 commit; 7 end; 8 /PL/SQL procedure successfully completed.SQL> select * from flash_test; ID NAME---------- ------------------------------ 1 oracle 2 oracle 3 oracle 4 oracle 5 oracle 6 oracle 7 oracle 8 oracle 9 oracle 10 oracle闪回查询正如前言中所提,Flashback Query 是利用多版本读一致性的特性从UNDO 表空间读取操作前的记录数据!什么是多版本读一致性Oracle 采用了一种非常优秀的设计,通过undo 数据来确保写不堵塞读,简单的讲,不同的事务在写数据时,会将数据的前映像写入undo 表空间,这样如果同时有其它事务查询该表数据,则可以通过undo 表空间中数据的前映像来构造所需的完整记录集,而不需要等待写入的事务提交或回滚。flashback query 有多种方式构建查询记录集,记录集的选择范围可以基于时间或基于scn,甚至可以同时查询出记录在undo 表空间中不同事务时的前映象。用法与标准查询非常类似,要通过flashback query 查询undo 中的撤销数据,最简单的方式只需要在标准查询语句的表名后面跟上as of timestamp(基于时间)或as of scn(基于scn)即可。as of timestamp|scn 的语法是自9iR2 后才开始提供支持。具体操作如下 :SQL> select sysdate from dual;SYSDATE-------------------2011-03-23 08:53:18SQL> conn / as sysdba;Connected.SQL> grant select on v_$database to hr;Grant succeeded.SQL> grant select on flashback_transaction_query to hr;Grant succeeded.SQL> select GRANTEE,TABLE_NAME,PRIVILEGE from user_tab_privs;GRANTEE TABLE_NAME PRIVILEGE---------- ------ --------------- ----------- ----------HR V_$DATABASE SELECTHR FLASHBACK_TRANS SELECT ACTION_QUERYHR DBMS_STATS EXECUTEOE COUNTRIES REFERENCESOE COUNTRIES SELECTOE LOCATIONS REFERENCESOE LOCATIONS SELECTOE DEPARTMENTS SELECTOE JOBS SELECTOE EMPLOYEES REFERENCESOE EMPLOYEES SELECTOE JOB_HISTORY SELECT查询当前SCNSQL> select current_scn from v$database;CURRENT_SCN--------------- 851281亦可用如下命令查询当前SCNselect dbms_flashback.get_system_change_number from dual;对表进行DML操作并提交SQL> delete from flash_test where id <3;2 rows deleted.SQL> commit;Commit complete.SQL> select * from flash_test; ID NAME---------- ------------------------------ 3 oracle 4 oracle 5 oracle 6 oracle 7 oracle 8 oracle 9 oracle 10 oracle8 rows selected.查询当前时间SQL> select sysdate from dual;SYSDATE-------------------2011-03-23 08:54:38基于时间点的闪回查询SQL> select * from flash_test as of timestamp (sysdate - 2/1440); ID NAME---------- ------------------------------ 3 oracle 4 oracle 5 oracle 6 oracle 7 oracle 8 oracle 9 ora cle 10 oracle 1 oracle 2 oracle10 rows selected.基于SCN的闪回查询SQL> select * from flash_test as of scn 851281; ID NAME---------- ------------------------------ 3 oracle 4 oracle 5 oracle 6 oracle 7 oracle 8 oracle 9 oracle 10 oracle 1 oracle 2 oracle10 rows selected.事实上,Oracle 在内部都是使用scn,即使你指定的是as of timestamp,oracle 也会将其转换成scn,系统时间标记与scn 之间存在一张表,即SYS 下的SMON_SCN_TIMESQL> desc sys.smon_scn_time; Name Null? Type ----------------------------------------- -------- ---------------------------- THREAD NUMBER TIME_MP NUMBER TIME_DP DATE SCN_WRP NUMBER SCN_BAS NUMBER NUM_MAPPINGS NUMBER TIM_SCN_MAP RAW(1200) SCN NUMBER ORIG_THREAD NUMBER每隔5 分钟,系统产生一次系统时间标记与scn 的匹配并存入sys.smon_scn_time 表,该表中记录了最近1440个系统时间标记与scn 的匹配记录,由于该表只维护了最近的1440 条记录,因此如果使用as of timestamp 的方式则只能flashback 最近5 天内的数据(假设系统是在持续不断运行并无中断或关机重启之类操作的话)。注意理解系统时间标记与scn 的每5 分钟匹配一次这句话,举个例子,比如scn:339988,339989 分别匹配08-05-3013: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 这个时刻的数据。具体可查看SCN 和 timestamp 之间的对应关系,读者仔细观察即可知道他们直接的对应关系:select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss')from sys.smon_scn_time;闪回版本查询所谓版本指的是每次事务所引起的数据行变化情况,每次变化就是一个版本。这些变化都是已经提交了的事务 引起的变化,没有提交的变化不会显示。Oracle 的闪回版本查询功能(Flashback Version Query)提供了一个 审计行改变的查询功能 ,它能找到所有 已提交行的记录 。借助这个特殊的功能,我们可以看到什么时间执行了什么操作。使用该功能,可以很轻松地实现对应用系统进行审计,而没有必要使用细粒度的审计功能或者是使用LOGMNR了。闪回版本查询功能依赖于AUM(Automatic Undo Management),AUM指的是采用撤销表空间记录来增、删、改数据的方法。要用Flashback Version Query实现对数据行改变记录进行查询,主要采用SELECT 语句带flashback_query子语句来实现,Flashback_query子语句的语法格式如下:SELECT [Pseudocolums]… FROM …VERSION BETWEEN[ SCN | TIMESTAMP ][ <expr> | MAXVALUE] AND <expr> | MINVALUE]| AS OF [SCN |TIMESTAMP ] <expr>where [Pseudocolums]其中各项参数的说明如下。l AS OF:表示恢复单个版本;l SCN:系统更改号;l TIMESTAMP:时间。Pseudocolumns为伪列,闪回版本查询中的 伪列有Versions_starttime :事务开始时间Versions_startscn :事务开始SCNVersions_endtime :事务结束时间Versions_endscn :事务结束SCNVersions_xid :事务的ID号Versions_operation :事务所进行的操作类型,包括插入(I)、删除(D)和更新(U)下面构造两个事务并通过闪回版本查询查询相关信息SQL> select current_scn from v$database;CURRENT_SCN----------- 854038SQL> insert into flash_test values(21,'Linux');1 row created.SQL> update flash_test set name='DBA' where id=5;1 row updated.SQL> commit;Commit complete.SQL> delete from flash_test where id >8;3 rows deleted.SQL> commit;Commit complete.SQL> select current_scn from v$database;CURRENT_SCN----------- 854093SQL> select versions_starttime vss,versions_startscn ves,versions_endtime vet,versions_endscn ves,versions_xid,versions_operation,id,name 2 from flash_test 3 versions between scn 854038 and 854093VSS VES VET VES VERSIONS_XID VER ID NAME----------------------- --------- ----------------------- ---------- -------------------------- --- -------- ---------23-MAR-11 10.43.01 AM 854088 020012009F010000 D 21 Linux23-MAR-11 10.43.01 AM 854088 020012009F010000 D 10 oracle23-MAR-11 10.43.01 AM 854088 020012009F010000 D 9 oracle23-MAR-11 10.42.46 AM 854082 0A0028006F010000 U 5 DBA23-MAR-11 10.42.46 AM 854082 23-MAR-11 854088 0A0028006F010000 I 21 Linux 10.43.01 AM 3 oracle 4 oracle(省略若干行)基于时间的闪回版本查询命令如下:SQL> select versions_starttime vss,versions_startscn ves,versions_endtime vet,versions_endscn ves,versions_xid,versions_operation,id,name 2 from flash_test 3 versions between timestamp to_date('2011-03-23 18:27:40','yyyy-mm-dd hh24:mi:ss') and to_date('2011-03-23 18:30:00','yyyy-mm-dd hh24:mi:ss');亦可使用versions between scn/timestamp minvalue and maxvalue where .....来查询数据行的所有变化,注意这里一定要加上where子句,否则无法成功SQL>select * from flash_test versions between scn minvalue and maxvalue where name='oracle';SQL>select * from flash_test versions between timestamp minvalue and maxvalue where name='oracle';闪回事务查询结合之前应用闪回版本查询得出的事务号可进行闪回事务查询获取撤销操作的SQL,同样的该查询也是利用UNDO表空间中的UNDO数据。注意,无论该事务提交与否,都能进行闪回事务查询SQL>select xid,start_scn,operation,undo_sql,row_id 2 from flashBack_transaction_query 3* where xid='020012009F010000'XID STARTSCN OPERATION UNDO_SQL ROW_ID---------------- ---------- ------------------- ----------------------------------------------------------- ---------------020012009F010000 854086 DELETE insert into "HR"."FLASH_TEST"("ID","NAME") values ('21','Linux'); AAAM6gAAEAAAAJEAAN 020012009F010000 854086 DELETE insert into "HR"."FLASH_TEST"("ID","NAME") values ('10','oracle'); AAAM6gAAEAAAAJEAAM020012009F010000 854086 DELETE insert into "HR"."FLASH_TEST"("ID","NAME") values ('9','oracle'); AAAM6gAAEAAAAJEAAJ 020012009F010000 854086 BEGIN复制UNDO_SQL中的数据执行即可得出撤销刚才进行的DML操作TIPs:查询flashback_transaction_query这个数据字典需要DBA角色或SELECT ANY TRANSACTION权限闪回表所谓闪回表,就是将表里的数据回退到历史上的某个时间点,比如回退用户误删除数据之前的时间点,从而将误删除的数据恢复回来。在这个操作过程中,数据库仍然可用,而且不需要额外的空间。由于闪回表的操作会修改表里的数据,从而有可能引起数据行的移动。比如某一行数据当前在A数据块里,而在把表闪回到以前的某个时间点时,在那个时间点上,该行数据在B数据块里。于是闪回表操作中,数据行从A数据块转移到了B数据块,因此,在闪回表之前,必须启用行迁移。SQL> select * from flash_test; ID NAME---------- -------------- 3 oracle 4 oracle 5 DBA 6 oracle 7 oracle 8 oracle6 rows selected.开启行移动SQL> alter table flash_test enable row movement;Table altered.关闭行移动SQL> alter table flash_test disable row movement;确认是否开启行移动SQL>select table_name,row_movement from user_tables where table_name='FLASH_TEST'TABLE_NAME ROW_MOVEMENT--------------- ------------------------FLASH_TEST ENABLED当前SCNSQL> select current_scn from v$database;CURRENT_SCN----------- 868741SQL> insert into flash_test values(100,'OCP');1 row created.SQL> COMMIT;Commit complete.SQL> select current_scn from v$database;CURRENT_SCN----------- 868752SQL> select * from flash_test; ID NAME---------- -------------- 100 OCP 3 oracle 4 oracle 5 DBA 6 oracle 7 oracle 8 oracle7 rows selected.进行基于SCN的闪回表SQL> flashback table flash_test to scn 868741;Flashback complete.基于时间的闪回表命令如下SQL> flashback table flash_test to timestamp to_date('2011-03-23 18:27:40‘,'yyyy-mm-dd hh24:mi:ss');SQL> select * from flash_test; ID NAME---------- -------------- 3 oracle 4 oracle 5 DBA 6 oracle 7 oracle 8 oracle6 rows selected.成功执行如果在闪回的两个SCN直接存在DDL操作,那么闪回表将不能成功闪回 。具体操作如下SQL> select current_scn from v$database;CURRENT_SCN----------- 869565SQL> select * from flash_test; ID NAME ---------- -------------- 3 oracle 4 oracle 5 DBASQL> delete from flash_test where id=3;1 row deleted.执行DDL操作SQL> alter table flash_test drop column name;Table altered.闪回到指定SCNSQL> flashback table flash_test to scn 869565;flashback table employees,flash_test to scn 870516 *ERROR at line 1:ORA-01466: unable to read data - table definition has changed修改并提交过数据之后,对表做过DDL 操作,包括:drop/modify 列, move 表, drop 分区(如果有的话), truncate table/partition,这些操作会另undo 表空间中的撤销数据失效,对于执行过这些操作的表应用flashback query 会触发ORA-01466 错误。另外一些表结构修改语句虽然并不会影响到undo 表空间中的撤销记录,但有可能因表结构修改导致undo 中重做记录无法应用的情况,比如对于增加了约束,而flashback query 查询出的undo 记录已经不符合新建的约束条件,这个时候直接恢复显然不可能成功,你要么暂时disable 约束,要么通过适当逻辑,对要恢复的数据进行处理之后,再执行恢复。几点需要注意的:1、 flashback query 对v$tables,x$tables 等动态性能视图无效,不过对于dba_*,all_*,user_*等数据字典是有效的。同时该特性也完全支持访问远端数据库,比如select * from tbl@dblink as of scn 360; 的形式。2、基于undo 的表恢复,flashback table 实际上做的也是dml 操作(会在被操作的表上加dml 锁),因此还需要注意triggers 对其的影响,默认情况下,flashback table to scn/timestamp 在执行时会自动disable 掉与其操作表相差的triggers,如果你希望在此期间trigger 能够继续发挥做用,可以在flashback table 后附加ENABLE TRIGGERS 子句。3、Flashback table 命令支持同时操作多个表,表名中间以逗号分隔即可,如果你执行一条 flashback table 命令时同时指定了多个表,要记住单个 flashback table 是在同一个事务中,因此这些表的恢复操作要么都成功,要么都失败。如: flashback table a,b ,c to scn 1103864;4、SYS用户不支持闪回表