数据误删后如何使用Flashback恢复数据

来源:互联网 发布:yum怎么读 编辑:程序博客网 时间:2024/04/29 16:57


Flashback Query

Flashback 是ORACLE 自9i 就开始提供的一项特性,在9i 中利用oracle 查询多版本一致的特点,
实现从回滚段中读取表一定时间内操作过的数据,可用来进行数据比对,或者修正意外提交造成的错误数据,该项特性也被称为Flashback Query。

一、Flashback Query
正如前言中所提,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 后才开始提供支持。


----实例测试:


1.as of timestamp 的示例
 
  17:05:08 scott@ORCL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
  
  Session altered.
  
  17:08:00 scott@ORCL> select sysdate from dual;
  
  SYSDATE
  -------------------
  2012-12-02 17:08:09
  
   
  17:08:09 scott@ORCL>  select * from test_ext;
  
  EMPLOYEE_ID FIRST_NAME LAST_NAME      JOB_ID     MANAGER_ID HIRE_DATE               SALARY COMMISSION_PCT DEPARTMENT_ID EMAIL
  ----------- ------------------------- ---------- ---------- ------------------- ---------- -------------- ------------- -------------------------
          360 Jane       Janus          ST_CLERK          121 2001-05-17 00:00:00       3000              0            50 jjanus
          361 Mark       Jasper         SA_REP            145 2001-05-17 00:00:00       8000             .1            80 mjasper
          362 Brenda     Starr          AD_ASST           200 2001-05-17 00:00:00       5500              0            10 bstarr
          363 Alex       Alda           AC_MGR            145 2001-05-17 00:00:00       9000            .15            80 aalda
          401 Jesse      Cromwell       HR_REP            203 2001-05-17 00:00:00       7000              0            40 jcromwel
          402 Abby       Applegate      IT_PROG           103 2001-05-17 00:00:00       9000             .2            60 aapplega
          403 Carol      Cousins        AD_VP             100 2001-05-17 00:00:00      27000             .3            90 ccousins
          404 John       Richardson     AC_ACCOUNT        205 2001-05-17 00:00:00       5000              0           110 jrichard
   
  ---模拟删除数据
 
  17:08:23 scott@ORCL>  delete from test_ext;
  
  8 rows deleted.
  
  17:08:52 scott@ORCL> commit;
  
  Commit complete.                                         
  
  17:08:55 scott@ORCL>   select * from test_ext;
  
  no rows selected
     

  ---查看删除之前的状态

  --假设当前举例删除数据已经有5分钟左右的时间(从实际测试的时间来看过了不到一分钟)

   
  17:11:10 scott@ORCL> select * from test_ext as of timestamp sysdate-3/1440;

  EMPLOYEE_ID FIRST_NAME   LAST_NAME    JOB_ID     MANAGER_ID HIRE_DATE               SALARY COMMISSION_PCT DEPARTMENT_ID EMAIL
  ----------- ------------ ------------ ---------- ---------- ------------------- ---------- -------------- ------------- -------------------------
          360 Jane         Janus        ST_CLERK          121 2001-05-17 00:00:00       3000              0            50 jjanus
          361 Mark         Jasper       SA_REP            145 2001-05-17 00:00:00       8000             .1            80 mjasper
          362 Brenda       Starr        AD_ASST           200 2001-05-17 00:00:00       5500              0            10 bstarr
          363 Alex         Alda         AC_MGR            145 2001-05-17 00:00:00       9000            .15            80 aalda
          401 Jesse        Cromwell     HR_REP            203 2001-05-17 00:00:00       7000              0            40 jcromwel
          402 Abby         Applegate    IT_PROG           103 2001-05-17 00:00:00       9000             .2            60 aapplega
          403 Carol        Cousins      AD_VP             100 2001-05-17 00:00:00      27000             .3            90 ccousins
          404 John         Richardson   AC_ACCOUNT        205 2001-05-17 00:00:00       5000              0           110 jrichard
  
  8 rows selected.
   
  ----或者如下:
  17:13:35 scott@ORCL> select * from test_ext as of timestamp to_timestamp('2012-12-02 17:07:00','yyyy-mm-dd hh24:mi:ss');                                                                                                                                                                                                                                                                                                                  
  EMPLOYEE_ID FIRST_NAME LAST_NAME     JOB_ID     MANAGER_ID HIRE_DATE               SALARY COMMISSION_PCT DEPARTMENT_ID EMAIL                    
  ----------- ------------------------ ---------- ---------- ------------------- ---------- -------------- ------------- -------------------------
          360 Jane       Janus         ST_CLERK          121 2001-05-17 00:00:00       3000              0            50 jjanus                   
          361 Mark       Jasper        SA_REP            145 2001-05-17 00:00:00       8000             .1            80 mjasper                  
          362 Brenda     Starr         AD_ASST           200 2001-05-17 00:00:00       5500              0            10 bstarr                   
          363 Alex       Alda          AC_MGR            145 2001-05-17 00:00:00       9000            .15            80 aalda                    
          401 Jesse      Cromwell      HR_REP            203 2001-05-17 00:00:00       7000              0            40 jcromwel                 
          402 Abby       Applegate     IT_PROG           103 2001-05-17 00:00:00       9000             .2            60 aapplega                 
          403 Carol      Cousins       AD_VP             100 2001-05-17 00:00:00      27000             .3            90 ccousins                 
          404 John       Richardson    AC_ACCOUNT        205 2001-05-17 00:00:00       5000              0           110 jrichard                 
          
  
  ---使用flashback query恢复delete数据
  
  17:14:00 scott@ORCL> insert into test_ext select * from test_ext as of timestamp sysdate-10/1440; 
                ---或者insert into test_ext select * from test_ext as of timestamp to_timestamp('2012-12-02 17:07:00','yyyy-mm-dd hh24:mi:ss'); 
                                                                                                 
  8 rows created.                                                                                  
                                                                                                 
  17:15:45 scott@ORCL> commit;                                                                     
                                                                                                 
  Commit complete.    
  
  如上述示例中所表示的,as of timestamp 的确非常易用,但是在某些情况下,我们建议使用as of scn 的方式执行flashback query,
  比如需要对多个相互有主外键约束的表进行恢复时,如果使用as of timestamp 的方式,可能会由于时间点不统一的缘故造成数据选择或插入失败,
  通过scn 方式则能够确保记录的约束一致性。
  
2.as of scn 示例
 
 --查看SCN:
  17:15:48 scott@ORCL> select current_scn from v$database;
  
  CURRENT_SCN
  -----------
       788923
  
  17:18:52 scott@ORCL> select dbms_flashback.get_system_change_number from dual;
  
  GET_SYSTEM_CHANGE_NUMBER
  ------------------------
                    788936

                                              
  17:19:16 scott@ORCL> delete from test_ext;    
                                                
  8 rows deleted.                                                                                                           
                                                
  17:20:29 scott@ORCL> commit;   
  
                 
  ---查看删除之前的状态:

  17:21:04 scott@ORCL>  select * from test_ext as of scn 788936;                                                                                                        
                                                                                                                                                                      
  EMPLOYEE_ID FIRST_NAME    LAST_NAME     JOB_ID     MANAGER_ID HIRE_DATE               SALARY COMMISSION_PCT DEPARTMENT_ID EMAIL                    
  ----------- ------------- ------------- ---------- ---------- ------------------- ---------- -------------- ------------- -------------------------
          360 Jane          Janus         ST_CLERK          121 2001-05-17 00:00:00       3000              0            50 jjanus                   
          361 Mark          Jasper        SA_REP            145 2001-05-17 00:00:00       8000             .1            80 mjasper                  
          362 Brenda        Starr         AD_ASST           200 2001-05-17 00:00:00       5500              0            10 bstarr                   
          363 Alex          Alda          AC_MGR            145 2001-05-17 00:00:00       9000            .15            80 aalda                    
          401 Jesse         Cromwell      HR_REP            203 2001-05-17 00:00:00       7000              0            40 jcromwel                 
          402 Abby          Applegate     IT_PROG           103 2001-05-17 00:00:00       9000             .2            60 aapplega                 
          403 Carol         Cousins       AD_VP             100 2001-05-17 00:00:00      27000             .3            90 ccousins                 
          404 John          Richardson    AC_ACCOUNT        205 2001-05-17 00:00:00       5000              0           110 jrichard                 
                                                                                                                                                               
  ------使用flashback query恢复delete数据
  
  17:21:29 scott@ORCL> insert into test_ext select * from test_ext as of scn 788936;

  8 rows created. 
    
 事实上,Oracle 在内部都是使用scn,即使你指定的是as of timestamp,oracle 也会将其转换成scn,
 系统时间标记与scn 之间存在一张表,即SYS 下的smon_scn_time
 
 
  17:24:26 scott@ORCL> 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


  select * from (
   select num_mappings,orig_thread,scn,scn_bas,scn_wrp,thread,time_dp,time_mp
   from sys.smon_scn_time
   order by time_dp desc
  )where rownum<11;
  
  NUM_MAPPINGS ORIG_THREAD        SCN    SCN_BAS    SCN_WRP     THREAD TIME_DP                TIME_MP
------------ ----------- ---------- ---------- ---------- ---------- ------------------- ----------
          85           0     789025     789025          0          0 2012-12-02 17:22:44  800990564
         100           0     788860     788860          0          0 2012-12-02 17:17:20  800990240
          83           0     788746     788746          0          0 2012-12-02 17:12:50  800989970
         100           0     788091     788091          0          0 2012-12-02 17:07:19  800989639
          97           0     787894     787894          0          0 2012-12-02 17:01:58  800989318
          79           0     787650     787650          0          0 2012-12-02 16:57:25  800989045
         100           0     787379     787379          0          0 2012-12-02 16:51:58  800988718
          89           0     787257     787257          0          0 2012-12-02 16:47:16  800988436
         100           0     787092     787092          0          0 2012-12-02 16:41:58  800988118
          82           0     786980     786980          0          0 2012-12-02 16:37:30  800987850
          
          
  每隔5 分钟,系统产生一次系统时间标记与scn 的匹配并存入sys.smon_scn_time 表,该表中记录了最近1440个系统时间标记与scn 的匹配记录,
  由于该表只维护了最近的1440 条记录,因此如果使用as of timestamp 的方式则只能flashback 最近5 天内的数据(假设系统是在持续不断运行并无中断或关机重启之类操作的话)。
  注意理解系统时间标记与scn 的每5 分钟匹配一次这句话,举个例子,比如scn:339988,339989 分别匹配2008-05-30 13:52:00 和2008-05-30 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 之间的对应关系:


  17:36:37 scott@ORCL> select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss')from sys.smon_scn_time
  17:40:00   2  where rownum<11;
  
         SCN TO_CHAR(TIME_DP,'YY
  ---------- -------------------
           4 2005-06-30 19:09:55
       10569 2005-06-30 19:10:41
      104863 2005-06-30 19:15:57
      142704 2005-06-30 19:20:13
      187891 2005-06-30 19:25:24
      232400 2005-06-30 19:28:00
      306630 2005-06-30 19:33:33
      322553 2005-06-30 19:35:45
      360021 2005-06-30 19:40:57
      361506 2005-06-30 19:41:10
    
  
  
  
  
          
0 0