zoukankan      html  css  js  c++  java
  • [Oracle 9i & 10g] Flashback Query, Flashback Version Query, Flashback Table, etc

    Oracle 9i 引入了flashback query,可以方便我们查询过去一个时间“点”的数据库的状态。比如我们在T1时刻更改了一条记录,接着在T2时刻删除了该条数据(并且commit了),我们可以通过flashback query来查询到T1时刻的该条记录。

    Oracle 10g把flashback query推进了一步,不光可以查询过去一个时间“点”的数据库状态, 而且可以查询过去一段时间内数据状态变化的过程(不同版本), 所以叫做flashback version query。

    不管是flashback query还是flashback version query, 所有的这些“历史数据”都保存在了Undo Segment上。 (在Orace 9i之前叫做rollback segment, 对应于手动来管理这部分空间)因此,我们可以查询到的历史数据受限于undo segment的大小(不太准确),因为undo segment在空间不够的时候会被覆写。当然,可以设置参数UNDO_RETENTION来设置数据在Undo Segment上的“存活”时间(单位是秒)。

    那么flashback query有啥好处呢? 这是个很容易想到的问题。 我觉得一个好处就是方便我们来undo我们之前做的“误”操作,比如我们不小心删除了一条数据并且commit了,很显然用rollback已经不起作用了,这个时候我们可以通过flashback query找到那个时刻的数据,把它重新插入到数据库中。(或者通过flashback table来直接恢复到之前的数据状态)

    那么我们如何查询到过去某个时刻的数据(从undo segment上)呢, Oracle 9i支持两种方式,一种是SCN(system change number),另外一种是timestamp。 Oracle10g R2 增加了一种方式,叫做restore point, 这个接下来都会介绍到。

    提到flashback, 可能会容易想到oracle 10g引入了flash recovery area(FRA)的概念,这个跟flashback query没有多大关系,FRA主要跟RMAN,数据库的恢复有关,具体可以参见这里

    同样,提到flashback, 还会想到oracle 10g R1 引入的flashback table。 从10g开始,用drop语句来删除一个数据库对象并不会直接把该数据库对象从数据库中彻底删除掉,而是把该数据库对象改了个名字放到了recyclebin中, 当然如果想彻底删除该数据库对象,可以在drop 的时候加上purge, 比如 drop table XXX purge,这样改数据库对象就不会放到recyclebin中,而是直接被删除了。正是因为数据库对象暂时保存在了recyclebin中,我们可以通过flashback语句来把该数据库对象恢复过来,例如 flashback table XXX to before drop. 对于这部分内容,最后再说,先从flashback query 谈起。

    1. Flashback Query in Oracle 9i (参考Adrian Billington的Flashback Query in Oracle 9i)

    Flashback query 在9.1 和9.2还是有点区别的,9.1的用法比较繁琐,不方便,9.2改进了许多。

    (1) 应用flashback query的先决条件

         undo_management = auto (在参数文件pfile/spfile中设置)

         undo_retention = n ( n是个正整数,单位是sec, 也是在参数文件pfile/spfile中设置)

         undo_tablespace = (也是在参数文件中设置)

         FLASHBACK 或者 FLASHBACK ANY的系统权限(system priviledge)

         执行DBMS_FLASHBACK的权限

    (2) 示例数据

    SQL> create table t
      2  as
      3  select owner, table_name, tablespace_name
      4  from all_tables
      5  where rownum <= 5;

    Table created.

    SQL> select * from t;

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ ----------------------
    --
    SYS                  ICOL$                          SYSTEM
    SYS                  CON$                           SYSTEM
    SYS                  UNDO$                          SYSTEM
    SYS                  PROXY_ROLE_DATA$               SYSTEM
    SYS                  FILE$                          SYSTEM

    SQL>

    【提示】在Oracle9i(9.1 和 9.2)中,Oracle建议我们等待大约5分钟之后再进行flashback query新创建的表,否则可能会碰到这个错误ORA-01466: unable to read data - table definition has changed. 注意这个5分钟时间间隔正好是9i 中SCN和timestamp相map的时间间隔,虽然可以用timestamp来进行flashback query,但实质还是根据该timestamp对应的SCN来进行flasbback query, 由于timestamp不是实时地跟SCN对应上, 因此我们需要等段时间来让timestamp跟SCN同步上, 因此用SCN会比timestamp更准确些。注意SCN会在每个commit的时候增长。

    (3) 9.1: DBMS_FLASHBACK

    在Oracle9i中,需要用到package DBMS_FLASHBACK来enable/disable FLASHBACK query。

    在进行操作之前,首先得到当前的SCN以便之后flashback query到这个时刻的数据,

    SQL> select dbms_flashback.get_system_change_number as scn from dual;

           SCN
    ----------
       1517851

    SQL>

    接下来对刚才创建的Table t做一些更改(并commit),

    SQL> update t set tablespace_name = LOWER(tablespace_name);

    5 rows updated.

    SQL> commit;

    Commit complete.

    SQL>

     

    可以看到数据发生了变化

    SQL> select * from t;

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ ------------------------
    --
    SYS                  ICOL$                          system
    SYS                  CON$                           system
    SYS                  UNDO$                          system
    SYS                  PROXY_ROLE_DATA$               system
    SYS                  FILE$                          system

    SQL>

    现在我们可以使用flashback query来得到我们更改之前的数据。(需要先用DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER(scn) 来把数据库设置成flashback 状态,之后我们就会看到这个SCN时的数据库状态)

    SQL> exec DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER(1517851);

    PL/SQL procedure successfully completed.

    SQL> select * from t;

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ ------------------
    --
    SYS                  ICOL$                                      SYSTEM
    SYS                  CON$                                       SYSTEM
    SYS                  UNDO$                                     SYSTEM
    SYS                  PROXY_ROLE_DATA$                SYSTEM
    SYS                  FILE$                                        SYSTEM

    SQL>

     

    可以看到tablespace_name的数据都变成更改之前的样子了。

    如果想看到数据库“实际”的状态,我们需要调用DBMS_FLASHBACK.DIABLE来离开flashback mode.

    SQL> exec DBMS_FLASHBACK.DISABLE;

    PL/SQL procedure successfully completed.

    SQL> select * from t;

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ -------------------
    --
    SYS                  ICOL$                          system
    SYS                  CON$                           system
    SYS                  UNDO$                          system
    SYS                  PROXY_ROLE_DATA$               system
    SYS                  FILE$                          system

    SQL>

     

     

    (4) 9.2 as of [SCN | timestamp]

     

    Oracle 9.2引入了新的机制来实现flashback query, 而不是9.1中那样需要手动去调用dbms_flaback中的存储过程。在Oracle 9.2中,我们可以直接通过SQL语句来实现,只需要加入(AS OF SCN xxx 或者 AS OF TIMESTAMP xxx) 就可以了。

    现在来看看刚才在9.1中的做法,如何在9.2中来实现,(这次更改table_name).

    SQL> alter session set NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY HH24:MI:SS.FF3';

    Session altered.

    SQL> select localtimestamp from dual;

    LOCALTIMESTAMP
    ---------------------------------------------------------------------------
    30-DEC-2009 10:51:11.656

    SQL> select * from t;

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ ---------------------------
    --
    SYS                  ICOL$                          system
    SYS                  CON$                           system
    SYS                  UNDO$                          system
    SYS                  PROXY_ROLE_DATA$               system
    SYS                  FILE$                          system

    SQL> update t set table_name = lower(table_name);

    5 rows updated.

    SQL> commit;

    Commit complete.

    SQL> select * from t;

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ ---------------------------
    SYS                  icol$                          system
    SYS                  con$                           system
    SYS                  undo$                          system
    SYS                  proxy_role_data$               system
    SYS                  file$                          system

    现在可以通过AS OF TIMESTAMP 来实现flashback query了。

    SQL> select * from t
      2  AS OF TIMESTAMP to_timestamp('30-DEC-2009 10:51:11.656');

    OWNER                TABLE_NAME                     TABLESPACE_NAME
    -------------------- ------------------------------ ------------------
    --
    SYS                  ICOL$                          system
    SYS                  CON$                           system
    SYS                  UNDO$                          system
    SYS                  PROXY_ROLE_DATA$               system
    SYS                  FILE$                          system

    很显然,这比在oracle 9.1中简单地多。

    2. Flashback Version Query in oracle 10g  (参考Adrian Billington的 flashback version query in oracle 10g)

    (1) 先创建需要的示例数据,

    SQL> create table fbt
      2  ( x integer,
      3    y timestamp,
      4    z varchar2(30));

    Table created.

    SQL> exec dbms_lock.sleep(10);

    PL/SQL procedure successfully completed.

    SQL> insert into fbt values(1, LOCALTIMESTAMP, 'Initial population');

    1 row created.

    SQL> commit;

    Commit complete.

     

    【注意】注意,这里用dbms_lock sleep了10秒钟,然后才插入数据(其实没啥关系,我认为)。 Oracle建议这么做,是为了避免遇到错误ORA-01466: unable to read data - table definition has changed。这个错误只有当flashback back query针对该刚刚建立的表执行时才会出现。

     

    (2) 对数据进行一系列的更改,并执行commit

    SQL> alter session set NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY HH24:MI:SS.FF3';

    Session altered.

    SQL> select LOCALTIMESTAMP as lower_bound from dual;

    LOWER_BOUND
    ---------------------------------------------------------------------------
    30-DEC-2009 11:35:03.981

    SQL> update fbt set y = LOCALTIMESTAMP, z = 'First update';

    1 row updated.

    SQL> commit;

    Commit complete.

    SQL> update fbt set y = LOCALTIMESTAMP, z = 'Second update';

    1 row updated.

    SQL> commit;

    Commit complete.

    SQL> select LOCALTIMESTAMP as upper_bound from dual;

    UPPER_BOUND
    ---------------------------------------------------------------------------
    30-DEC-2009 11:36:32.999

    SQL> delete from fbt where x = 1;

    1 row deleted.

    SQL> commit;

    Commit complete.

    SQL> select * from fbt;

    no rows selected

     

     

    (3) Flashback version query

     

    虽然现在表fbt里面没有数据,但是可以通过flashback version query来查到之前的“历史变化”数据。 Flashback version query是通过from语句的扩展语句 versions between. 有两种形式的versions between

     

    VERSIONS BETWEEN TIMESTAMP [lower bound] AND [upper bound]

    VERSIONS BETWEEN SCN [lower bound] AND [upper bound]

     

    lower bound/ upper bound 可以是具体的timestamp/scn, 也可以是关键字minvalue/maxvalue. 这些关键字让Oracle去找到所有的versions, 当然这要受制于undo_retention参数设置的大小,毕竟这部分信息是放在undo segment上的。

     

    SQL> select x, y, z
      2  from fbt VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE
      3  order by  y;

             X Y                                                      Z
    ---------- ------------------------------ ------------------------------
             1 30-DEC-2009 11:33:58.667       Initial population
             1 30-DEC-2009 11:35:27.374       First update
             1 30-DEC-2009 11:36:15.373       Second update
             1 30-DEC-2009 11:36:15.373       Second update

     

    从结果可以看出,之前做的操作都去取出来了,但是注意Second update出现了两条记录,这个有点奇怪。 还好flashback version query提供了一些pseudo-columns来帮助我们分析,参见下一部分。

     

    (3) Versions pseudo-columns

     

    Oracle 10g提供了一些pseudo-columns来帮助我们分析每个version的数据,

    • VERSIONS_STARTTIME (start timestamp of version);
    • VERSIONS_STARTSCN (start SCN of version);
    • VERSIONS_ENDTIME (end timestamp of version);
    • VERSIONS_ENDSCN (end SCN of version);
    • VERSIONS_XID (transaction ID of version); and
    • VERSIONS_OPERATION (DML operation of version).

     

    我们可以通过查询这些pseudo columns来获知每个版本的数据信息,

     

    SQL>

      1  select z,
      2    versionS_starttime,
      3    versionS_endtime,
      4    versionS_xid,
      5    versionS_operation
      6  from fbt VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE
      7* order by versions_endtime
    SQL> /

     

    Z                              VERSIONS_STARTTIME             VERSIONS_ENDTIME               VERSIONS_XID                   VERSIONS_OPERATION
    ------------------------------ ------------------------------ ------------------------------ ------------------------------ -------------------

    Initial population             30-DEC-2009 11:33:57.000       30-DEC-2009 11:35:39.000       06001B004C030000               I
    First update                   30-DEC-2009 11:35:39.000       30-DEC-2009 11:36:18.000       0900100063030000               U
    Second update                  30-DEC-2009 11:36:18.000       30-DEC-2009 11:36:54.000       0100250048030000              U
    Second update
                      30-DEC-2009 11:36:54.000                                      0900070063030000              D

     

     

    从这里可以看到,两条Second update 其实是对应两个操作,一个是update (U), 还有一个是Delete (D)。

    从这个记录同时可以看出删除操作是最后一步,因为对应的VERSIONS_ENDTIME是NULL。

    (4) Flashback transaction query

    Oracle 还提供了一个新的视图, FLASHBACK_TRANSACTION_QUERY 来提供更多的关于data version的信息。查询这个视图需要SELECT ANY TRANSACTION 的系统权限。

    SQL> desc flashback_transaction_query
     Name                          Null?    Type
     ----------------------------- -------- --------------------
     XID                                    RAW(8)
     START_SCN                              NUMBER
     START_TIMESTAMP                        DATE
     COMMIT_SCN                             NUMBER
     COMMIT_TIMESTAMP                       DATE
     LOGON_USER                             VARCHAR2(30)
     UNDO_CHANGE#                           NUMBER
     OPERATION                              VARCHAR2(32)
     TABLE_NAME                             VARCHAR2(256)
     TABLE_OWNER                            VARCHAR2(32)
     ROW_ID                                 VARCHAR2(19)
     UNDO_SQL                               VARCHAR2(4000)

     

     

    (5) Timestamp 和 SCN 之间的转换

    Oracle 10g提供了两个函数TIMESTAMP_TO_SCN和SCN_TO_TIMESTAMP来进行timestamp 和 scn之间的转换。 SCN 可以通过dbms_flashback.get_system_change_number来得到, timestamp可以通过localtimestamp和systimestamp来获得。

     

    SQL> alter session set NLS_TIMESTAMP_FORMAT='DD-MON-YYYY HH24:MI:SS.FF3';

    Session altered.

    SQL> select SYSTIMESTAMP, LOCALTIMESTAMP,
      2     DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER as scn
      3  from dual;

    SYSTIMESTAMP                                                                LOCALTIMESTAMP
                                                           SCN
    --------------------------------------------------------------------------- ------------------------
    --------------------------------------------------- ----------
    30-DEC-09 03.18.41.955000 PM +08:00                                         30-DEC-2009 15:18:41.955
                                                               1537555

     

    SQL> select SCN_TO_TIMESTAMP(1537555) as ts from dual;

    TS
    ---------------------------------------------------------------------------
    30-DEC-2009 15:18:39.000

    SQL> select TIMESTAMP_TO_SCN('30-DEC-2009 15:18:39.000') from dual;

    TIMESTAMP_TO_SCN('30-DEC-200915:18:39.000')
    -------------------------------------------
                                        1537555

     

     

     

    3. Flashback table in 10g (参考Adrian Billington的 flashback table in 10g)

     

    Oracle 10g 引入了flashback table 和 flashback database, 这里只cover flashback table部分。

    Flashback table 跟 Flashback query的区别在于, flashback table会把表中的数据永久地恢复到之前的状态,而flashback query并没有对表中的数据进行恢复,而只是返回之前时刻的数据。

     

    (1) 准备工作

     

    SQL> drop table t purge;

    Table dropped.

    SQL> create table t
      2  nologging
      3  enable row movement
      4  as
      5    select object_type as x
      6    from all_objects;

    Table created.

    为了可以把一个表flashback to 之前的一个状态,需要满足两个条件

    > 该表必须是enable row movement的, 因为flashback 一个表的时候,表中每条记录的rowid会发生变化。这可以通过alter table或在创建表的时候指定,如上例。

    > 执行操作的user要有FLASHBACK ANY TABLE的系统权限,或者目标表被赋予了改权限。

    创建好表之后,最好等几分钟让SCN增加。如果尝试去flashback一个新创建的表,可能会遇到ORA-01466: unable to read data - table definition has changed

     

     

    (2) Flashback to a previous state

     

    Flashback table主要是一个数据库恢复的方法,一般用来恢复被误删除的表中数据或整个表。

     

    首先删除表t中记录为PACKAGE的数据,并commit,

     

    SQL> delete from t where x = 'PACKAGE';

    1204 rows deleted.

    SQL> commit;

    Commit complete.

    SQL> select count(*) from t where x = 'PACKAGE';

      COUNT(*)
    ----------
             0

     

    现在可以通过flashback table来让表t回到之前的状态, (两分钟之前)

     

    SQL> flashback table t to TIMESTAMP systimestamp - interval '2' minute;

    Flashback complete.

    SQL> select count(*) from t where x = 'PACKAGE';

      COUNT(*)
    ----------
          1204

     

    我们也可以用SCN来让flashback table回到之前的某个SCN状态,

     

    SQL> var scn number;
    SQL> begin
      2    :scn := TIMESTAMP_TO_SCN(SYSTIMESTAMP);
      3  end;
      4  /

    PL/SQL procedure successfully completed.

    SQL> delete from t where x = 'PACKAGE';

    1204 rows deleted.

    SQL> select count(*) from t where x = 'PACKAGE';

      COUNT(*)
    ----------
             0

    SQL> FLASHBACK TABLE t to SCN :scn;

    Flashback complete.

    SQL> select count(*) from t where x = 'PACKAGE';

      COUNT(*)
    ----------
          1204

    SQL>

     

     

    (3) flashback data, not structure

     

    需要注意的是,flashback table只是恢复数据,并不会对表的schema的变化有啥影响。

     

    给表t增加一列new_column,

    SQL> alter table t add new_column integer default 0;

    Table altered.

    SQL> update t set x = 'MODIFIED';

    61883 rows updated.

    SQL> commit;

    Commit complete.

    SQL> select * from t where rownum <= 10;

    X                   NEW_COLUMN
    ------------------- ----------
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0
    MODIFIED                     0

    10 rows selected.

     

    flashback table到2分钟之前,

    SQL> flashback table t to timestamp (systimestamp - interval '2' minute);

    Flashback complete.

    SQL> select * from t where rownum <= 10;

    X                   NEW_COLUMN
    ------------------- ----------
    TABLE
    INDEX
    TABLE PARTITION
    TABLE
    INDEX
    TABLE
    INDEX
    TABLE PARTITION
    TABLE
    INDEX

    10 rows selected.

     

    可以看到列x中的数据恢复到之前的状态吗,但是新增加的列new_column还是在的,并没有消失(虽然该列的数据都没有了)。

     

    那么Oracle是如何来实现这个flashback table的feature的呢?

    可以通过下面的SQL语句查看新创建的数据对象有哪些,

    SQL> select owner, object_name, object_type, temporary
      2  from dba_objects
      3  where created > trunc(sysdate);

    OWNER                OBJECT_NAME   OBJECT_TYPE         T
    -------------------- -------------------------------------------------------------------------
    FRANK                SYS_TEMP_FBT
                                                  TABLE                             Y
    FRANK                FBT
                                                  TABLE                             N
    FRANK                T
                                                  TABLE                             N

     

    抛开表FBT不看(上一个部分中用到的这个表),除了表T,还有一个global temporary table SYS_TEMP_FBT. 这个表显然是Oracle自己创建的。

    该表结构如下,

     

    SQL> desc SYS_TEMP_FBT;
    Name
                                                                           Null?    Type
    ---------------------------------------------------------------------------------------------

    SCHEMA
                                                                                    VARCHAR2(32)
    OBJECT_NAME
                                                                                    VARCHAR2(32)
    OBJECT#
                                                                                    NUMBER
    RID
                                                                                    ROWID
    ACTION
                                                                                    CHAR(1)

    其中一部分数据如下 (用Sample语句),

    SQL> select * from sys_temp_fbt sample(0.01);

    SCHEMA     OBJECT_NAM    OBJECT# RID                  A
    ---------- ---------- ---------- -------------------- -
    FRANK      T               70534 AAAROGAAIAAAABKAGN   D
    FRANK      T               70534 AAAROGAAIAAAABTAHc   I
    FRANK      T               70534 AAAROGAAIAAAABVAHK   I
    FRANK      T               70534 AAAROGAAIAAAABqAEX   I
    FRANK      T               70534 AAAROGAAIAAAACOAA8   D
    FRANK      T               70534 AAAROGAAIAAAAEPAEy   D
    FRANK      T               70534 AAAROGAAIAAAAEbACE   I
    FRANK      T               70534 AAAROGAAIAAAAEbACL   I
    FRANK      T               70534 AAAROGAAIAAAAE2AKF   D
    FRANK      T               70534 AAAROGAAIAAAAFDAEc   I

    10 rows selected.

    这个表中的数据是在进行flashback table操作的时候产生的。其实这个表(sys_temp_fbt)也是在第一次进行flashback table 操作的时候生成的。

    SQL> select action, count(*) from sys_temp_fbt group by action;

    A   COUNT(*)
    - ----------
    I      61883
    D      61883

    SQL> select count(*) from t;

      COUNT(*)
    ----------
         61883

     

    根据Action (I -- insert, D-- Delete)的行数,可以看出,每次flashback table的时候,oracle会先把数据删除,然后再重新插入之前时刻的数据(通过flashback query).

     

    重新创建个小表来再看下,如下

     

    SQL>

      1  create table test
      2 
    enable row movement
      3  as
      4   select rownum r
      5  from dual
      6* connect by rownum <= 10
    SQL> /

    Table created.

    SQL> select * from test;

             R
    ----------
             1
             2
             3
             4
             5
             6
             7
             8
             9
            10

    10 rows selected.

    删除4条记录,剩余6条。 

    SQL> delete from test where rownum < 5;

    4 rows deleted.

    SQL> commit;

    Commit complete.

     

    进行flashback table操作

     

    SQL> flashback table test to timestamp systimestamp - interval '1' minute;

    Flashback complete.

    SQL> select * from test;

             R
    ----------
             1
             2
             3
             4
             5
             6
             7
             8
             9
            10

    10 rows selected.

    SQL> select object_name, object_type, temporary from dba_objects
      2  where created > trunc(sysdate);

    OBJECT_NAM OBJECT_TYPE         T
    ---------- ------------------- -
    SYS_TEMP_F TABLE               Y
    BT

    TEST       TABLE               N
    FBT        TABLE               N
    T          TABLE               N

     

    可以看出SYS_TMEP_FBT只存在一张,而且其中的数据随着每次flashback table操作而重置。

     

    SQL> select action, count(*) from sys_temp_fbt group by action;

    A   COUNT(*)
    - ----------
    I         10
    D          6

    SQL> select * from sys_temp_fbt order by rid;

    SCHEMA     OBJECT_NAM    OBJECT# RID                  A
    ---------- ---------- ---------- -------------------- -
    FRANK      TEST            70724 AAARREAAIAAAACUAAA   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAB   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAC   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAD   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAE   D
    FRANK      TEST            70724 AAARREAAIAAAACUAAE   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAF   D
    FRANK      TEST            70724 AAARREAAIAAAACUAAF   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAG   D
    FRANK      TEST            70724 AAARREAAIAAAACUAAG   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAH   D

    SCHEMA     OBJECT_NAM    OBJECT# RID                  A
    ---------- ---------- ---------- -------------------- -
    FRANK      TEST            70724 AAARREAAIAAAACUAAH   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAI   D
    FRANK      TEST            70724 AAARREAAIAAAACUAAI   I
    FRANK      TEST            70724 AAARREAAIAAAACUAAJ   D
    FRANK      TEST            70724 AAARREAAIAAAACUAAJ   I

    16 rows selected.

    SQL>

     

    可以看到对每行记录都是先进行删除,然后再插入。

    最大疑问: 为什么需要这张SYS_TEMP_FBT来记录flashback table的操作呢? 我想完全可以在执行flashback table的时候,首先把该表中的数据全部删除,然后插入flashback query得到的数据。待研究研究……

    (3) Flashback drop

    可以用Flashback drop来恢复一个被删除的表,

    SQL> drop table test;

    Table dropped.

    SQL> flashback table test to before drop;

    Flashback complete.

    SQL> select * from test;

             R
    ----------
             1
             2
             3
             4
             5
             6
             7
             8
             9
            10

    10 rows selected.

     

    (4) Recycle bin

    从Oracle10g开始,用drop删除的数据库对象并没有真正从数据库中删除掉,而是被放到了recycle bin中了,也是藉此,flashback table to before drop才可以work.

    SQL> DESC recyclebin
     Name                                      Null?    Type
     ----------------------------------------- -------- ----------------------------
     OBJECT_NAME                               NOT NULL VARCHAR2(30)
     ORIGINAL_NAME                                      VARCHAR2(32)
     OPERATION                                          VARCHAR2(9)
     TYPE                                               VARCHAR2(25)
     TS_NAME                                            VARCHAR2(30)
     CREATETIME                                         VARCHAR2(19)
     DROPTIME                                           VARCHAR2(19)
     DROPSCN                                            NUMBER
     PARTITION_NAME                                     VARCHAR2(32)
     CAN_UNDROP                                         VARCHAR2(3)
     CAN_PURGE                                          VARCHAR2(3)
     RELATED                                   NOT NULL NUMBER
     BASE_OBJECT                               NOT NULL NUMBER
     PURGE_OBJECT                              NOT NULL NUMBER
     SPACE                                              NUMBER
    

    SQL> drop table test;

    Table dropped.

    SQL> flashback table test to before drop rename to test_t;

    Flashback complete.

    SQL> select * from test_t;

             R
    ----------
             1
             2
             3
             4
             5
             6
             7
             8
             9
            10

    10 rows selected.

     

     

    4. Flashback Restore Points in Oracle 10g R2 (参考Adrian Billington的 flashback restore point in 10.2

    Oracle 10g R1 引入了flashback table, 可以通过SCN或Timestamp来进行数据的恢复或者undrop被删除的表。10g R2引入了Restore Point来提供另外一种flashback table 的方式。

    (1) Restore Points

    Restore points, 说白了,就是你定义一个容易记住的名字来标示你将来想让表flashback到什么地方,因为SCN, timestamp相对来说更不容易记忆,不直观。但Oracle最终还是根据SCN来做flashback。

    根据文档说明,可以创建最多2048个命名的resotred points. restore points 可以是 normal 或 guaranteed.  Guaranteed的restore point用在flashback dabatase中。

    (2) Privileges

    创建restore point需要以下权限,

    SELELCT ANY DICTIONARY

    FLASHBACK ANY TABLE

    (3) 准备数据

    SQL> drop table t;

    Table dropped.

    SQL> create table t(x, y, z)
      2  enable row movement
      3  as
      4    select object_id, object_name, object_type
      5    from all_objects
      6    where rownum <= 5;

    Table created.

    SQL> select * from t;

             X Y                              Z
    ---------- ------------------------------ ----------------
            20 ICOL$                          TABLE
            44 I_USER1                        INDEX
            28 CON$                           TABLE
            15 UNDO$                          TABLE
            29 C_COBJ#                        CLUSTER

     

    (4) Creating and Using a restore point

    创建一个restore point – before_we_do_anything

    SQL> create restore point before_we_do_anything;

    Restore point created.

     

    先删除2条数据,并commit.
    SQL> delete from t where rownum <= 2;

    2 rows deleted.

    SQL> commit;

    Commit complete.

    SQL> select * from t;

             X Y                              Z
    ---------- ------------------------------ -------------------
            28 CON$                           TABLE
            15 UNDO$                          TABLE
            29 C_COBJ#                        CLUSTER

     

    现在用restore point来flashback table.

    SQL> flashback table t to restore point before_we_do_anything;

    Flashback complete.

    SQL> select * from t;

             X Y                              Z
    ---------- ------------------------------ -------------------
            20 ICOL$                          TABLE
            44 I_USER1                        INDEX
            28 CON$                           TABLE
            15 UNDO$                          TABLE
            29 C_COBJ#                        CLUSTER

     

    删除restore point before_we_do_anything.

    SQL> drop restore point before_we_do_anything;

    Restore point dropped.

    (5) Metadata

    注意restore point并不是一个database object,从视图dba_objects里面是查不到的。但是Oracle提供了一个动态视图v$restore_point来查看restore point的信息。

    SQL> desc v$restore_point;
    Name
                                                                           Null?    Type
    ---------------------------------------------------------------------------------------------
     
    SCN
                                                                                    NUMBER
    DATABASE_INCARNATION#
                                                                                    NUMBER
    GUARANTEE_FLASHBACK_DATABASE
                                                                                    VARCHAR2(3)
    STORAGE_SIZE
                                                                                    NUMBER
    TIME
                                                                                    TIMESTAMP(9)
    NAME
                                                                                    VARCHAR2(128)

    SQL>

    (6) Retention target

    参数db_flashback_retention_target决定可以恢复到多久之前的restore point。

    Normal restore point 在超过参数control_file_record_keep_time设置的时间后会被自动删除 (guaranteed restore point需要手动来删除)

    SQL> show parameter DB_FLASHBACK_RETENTION_TARGET
    
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------------------------
    db_flashback_retention_target        integer     1440
    
    SQL> show parameter CONTROL_FILE_RECORD_KEEP_TIME
    
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------------------------
    control_file_record_keep_time        integer     7
    
  • 相关阅读:
    9.8 查找表
    LeetCode——Permutations
    利用rman自己主动备份转储spfile
    linux下非root用户怎样改动root权限的文件
    做一个有主见的女生
    APP-FND-00676: 弹性域例程 FDFGDC 无法读取为此说明性弹性域指定的默认引用字段
    矩阵高速幂模板篇
    Index statistics collected bug
    位运算
    poj 1190 生日蛋糕 , 强剪枝
  • 原文地址:https://www.cnblogs.com/fangwenyu/p/1636263.html
Copyright © 2011-2022 走看看