自动启用表的FLASHBACK ARCHIVE

时间:2015-05-14 02:16:20   收藏:0   阅读:255
Oracle的Flashback特性能让你找回先前的数据,因为这个特性依赖于UNDO,所以它的使用也是有很多限制的,比如当表的结构发生变化后, 如删除了一个字段(增加字段Flashback还能使用),
那Flashback的特性就不能发挥作用了。当你使用Flashback时就会抛出ORA-01466的错误,提示表的定义已更改:
08:09:16 SQL> select timestamp_to_scn(to_timestamp(sysdate,‘yyyy-mm-dd hh24:mi:ss‘)) scn from dual;

                    SCN
-----------------------
          6054997065323
  
08:10:00 SQL> alter table YKSOFT.USRA04_BAK20090814 add testcol VARCHAR2(30);

Table altered.

08:10:22 SQL> ALTER TABLE YKSOFT.USRA04_BAK20090814 DROP COLUMN testcol;

Table altered.

08:10:35 SQL> select count(*) from YKSOFT.USRA04_BAK20090814 as of scn 6054997065323;
select count(*) from YKSOFT.USRA04_BAK20090814 as of scn 6054997065323
                            *
ERROR at line 1:
ORA-01466: unable to read data - table definition has changed

针对这个不足,Oracle在11g中引入了一个新的特性Flashback Data Archive,也叫做Oracle Total Recall。该特性支持在ADD/DROP/MODIFY/RENAME表字段,或者ADD/DROP/RENAME表的约束,
或者TRUNCATE表后,仍然能正确使用Flashback Query,而不会报错:
08:09:16 SQL> select timestamp_to_scn(to_timestamp(sysdate,‘yyyy-mm-dd hh24:mi:ss‘)) scn from dual;

                    SCN
-----------------------
          6054997065323
  
08:10:52 SQL> alter table yksoft.USRAZQ add testcol VARCHAR2(30);

Table altered.

08:11:16 SQL> alter table yksoft.USRAZQ drop COLUMN testcol;

Table altered.

08:11:37 SQL> select count(*) from yksoft.USRAZQ as of scn 6054997065323;

  COUNT(*)
----------
       132

1 row selected.

但是Flashback Archive是针对表的,也就是说如果你要启用Flashback Archive,你需要对每个表进行设置:ALTER TABLE XXX.XXXX FLASHBACK ARCHIVE [flashback_archive],如果应用
的表基本不会增加/删除,那么一次初始化启用表的Flashback Archive也就可以了。但是有些应用,就比如我现在碰到的,时不时的就会CREATE一下表,时不时的就会DROP一下表,时不时的就
会ALTER一下表,然后还时不时的有XX用户邮件过来说不小心删错数据了,帮我恢复到之前的时间XXX,这时悲剧就发生了Flashback显然已经失效,又得花一番功夫去恢复了。此处省略1万字。。。
也就是基于这个原因,才会想到去实现一个自动启用表的FLASHBACK ARCHIVE的方案。该方案基于Oracle的System Trigger。

首先创建一个AFTER CREATE的Trigger:
CREATE OR REPLACE PROCEDURE SYS.ENABLE_TAB_FLA 
(
  object_owner IN VARCHAR2,  
  object_name  IN VARCHAR2,
  fla_name     IN VARCHAR2
) IS
  opsql         VARCHAR2(128);
BEGIN
  opsql := ‘ALTER TABLE ‘||object_owner||‘.‘||object_name||‘ FLASHBACK ARCHIVE ‘||fla_name;
  EXECUTE IMMEDIATE opsql;
END;
/

CREATE OR REPLACE TRIGGER SYS.ENABLE_TAB_FLA_TRIG
AFTER CREATE ON DATABASE
DECLARE
  operation    VARCHAR2(30);
  object_owner VARCHAR2(30);
  object_name  VARCHAR2(128);
  object_type  VARCHAR2(30);
  sql_list     ora_name_list_t;
  sql_i        binary_integer;
  sql_text     VARCHAR2(4000);
  attempt_by   VARCHAR2(30);
  fired        VARCHAR2(3);
  comment_text VARCHAR2(2000);
  attempt_dt   DATE;
  fla          VARCHAR2(30);
  
BEGIN
  operation := ora_sysevent;
  object_owner := ora_dict_obj_owner;
  object_name := ora_dict_obj_name;
  object_type := ora_dict_obj_type;
  sql_i := ora_sql_txt(sql_list);
  FOR i IN 1..sql_i LOOP
    sql_text := sql_text || sql_list(i);
  END LOOP;
  attempt_by := USER;
  fired := ‘NO‘;
  attempt_dt := SYSDATE;
  
  IF (operation = ‘CREATE‘) AND (object_owner = ‘YKSOFT‘) AND (object_type = ‘TABLE‘) AND (SUBSTR(object_name, 1, 4) IN (‘USRA‘, ‘RETA‘))  THEN
      fla := ‘YKFLA‘;
  ENABLE_TAB_FLA(object_owner, object_name, fla);
  fired := ‘YES‘;
  comment_text := ‘Flashback Archive was enabled for ‘||object_owner||‘.‘||object_name||‘ on ‘||fla;
  TRI_LOG (operation, object_owner, object_name, object_type, sql_text, attempt_by, fired, comment_text, attempt_dt); -- 记录日志
  END IF;

EXCEPTION
  WHEN OTHERS THEN
  comment_text := sqlerrm;
  TRI_LOG (operation, object_owner, object_name, object_type, sql_text, attempt_by, fired, comment_text, attempt_dt);
END;
/

我这里创建的是DATABASE级的Trigger,当然你也可以创建SCHEMA TRIGGER(但是SCHEMA TRIGGER不一定生效)。然后在Trigger根据实际的需要对表启用Flashback Archive。
到这里,其实已经完成自动启用表的FLASHBACK ARCHIVE的功能,但是还有一点也必须考虑到,就是在DROP表时。如果在一张已启用Flashback Archive的表上进行DROP操作,就会报ORA-55610错误
SQL> DROP TABLE YKSOFT.USRA01AT;
DROP TABLE YKSOFT.USRA01AT
                  *
ERROR at line 1:
ORA-55610: Invalid DDL statement on history-tracked table

也就是说在DROP表之前,先要禁用该表的Flashback Archive。所以这里创建一个BEFORE DROP的Trigger:
CREATE OR REPLACE PROCEDURE SYS.DISABLE_TAB_FLA 
(
  object_owner IN VARCHAR2,  
  object_name  IN VARCHAR2
) IS
  PRAGMA AUTONOMOUS_TRANSACTION;
  opsql         VARCHAR2(128);
BEGIN
  opsql := ‘ALTER TABLE ‘||object_owner||‘.‘||object_name||‘ NO FLASHBACK ARCHIVE‘;
  EXECUTE IMMEDIATE opsql;
  COMMIT;
END;
/

CREATE OR REPLACE TRIGGER SYS.DISABLE_TAB_FLA_TRIG
BEFORE DROP ON DATABASE
DECLARE
  operation    VARCHAR2(30);
  object_owner VARCHAR2(30);
  object_name  VARCHAR2(128);
  object_type  VARCHAR2(30);
  sql_list     ora_name_list_t;
  sql_i        binary_integer;
  sql_text     VARCHAR2(4000);
  attempt_by   VARCHAR2(30);
  fired        VARCHAR2(3);
  comment_text VARCHAR2(2000);
  attempt_dt   DATE;
  opsql        VARCHAR2(128);
  
BEGIN
  operation := ora_sysevent;
  object_owner := ora_dict_obj_owner;
  object_name := ora_dict_obj_name;
  object_type := ora_dict_obj_type;
  sql_i := ora_sql_txt(sql_list);
  FOR i IN 1..sql_i LOOP
    sql_text := sql_text || sql_list(i);
  END LOOP;
  attempt_by := USER;
  fired := ‘NO‘;
  attempt_dt := SYSDATE;
  
  IF (operation = ‘DROP‘) AND (object_owner = ‘YKSOFT‘) AND (object_type = ‘TABLE‘) AND (SUBSTR(object_name, 1, 4) IN (‘USRA‘, ‘RETA‘))  THEN
  DISABLE_TAB_FLA(object_owner, object_name);
  fired := ‘YES‘;
  comment_text := ‘Flashback Archive was disable for ‘||object_owner||‘.‘||object_name;
  TRI_LOG (operation, object_owner, object_name, object_type, sql_text, attempt_by, fired, comment_text, attempt_dt);
  END IF;
  
EXCEPTION
  WHEN OTHERS THEN
  comment_text := sqlerrm;
  TRI_LOG (operation, object_owner, object_name, object_type, sql_text, attempt_by, fired, comment_text, attempt_dt);
END;
/

BEFORE DROP的Trigger里很重要的一点是需要创建一个自治事务(PRAGMA AUTONOMOUS_TRANSACTION)的过程来支持禁用Flashback Archive的操作,否则就会报ORA-30512的错误:
SQL> DROP TABLE YKSOFT.RETA01AT;
DROP TABLE YKSOFT.RETA01AT
                  *
ERROR at line 1:
ORA-30512: cannot modify YKSOFT.RETA01AT more than once in a transaction

而且过程中的COMMIT也是必须的,否则还是报错。至此,一个比较完整的自动启用表的FLASHBACK ARCHIVE方案也就实现了。当然还有一些操作,如ALTER TABLE MOVE/ALTER TABLE UPGRADE也会引发和DROP一样的错误,这可以根据实际需要再去完善了。

原文:http://blog.itpub.net/13885898/viewspace-1651394/

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!