转自:http://book.2cto.com/201209/4154.html
闪回查询对撤销数据及参数undo_retention的依赖注定了它们在大事务量的情况下闪回时间窗口将会很小,想要查询数月之前的“旧”数据绝对不可能,但在闪回数据归档面前这并不是不可能的。
闪回数据归档的工作原理是将原本只能保存在UNDO表空间的撤销数据额外的以一种历史表的形式保存在指定的普通表空间(permanent类型的表空间)中。并且不像undo_retention参数那样是个影响整个数据库的设置,闪回数据归档可以只为特定的表服务,这样就可以长时间地保存感兴趣的“旧”数据了。比如,在USERS表空间中创建一个能够将“旧”数据保存1年的数据归档,取名为“FDA1”,操作者必须拥有“flashback archive administer”系统权限:
SQL> create flashback archive fda1 tablespace users retention 1 year;
Flashback archive created.
或者创建一个默认的闪回数据归档,取名为“fda_default”,操作者必须拥有SYSDBA权限:
SQL> create flashback archive default fda_default tablespace users retention 1 year;
Flashback archive created.
有了归档,就可以使用“flashback archive”子句在特定的表上启用闪回数据归档功能了。比如,让hr.employees使用fda1,从此该表的修改历史将保留1年:
SQL> alter table hr.employees flashback archive fda1;
Table altered.
若执行以上命令的是个普通账号,比如HR用户,那么其在执行命令前必须被授予“flashback archive”对象权限,比如:
SQL> grant flashback archive on fda1 to hr;
Grant succeeded.
若有默认的闪回数据归档,则启用时不必给出其名称。比如,让hr.departments使用默认的FDA,从此该表的修改历史也将保留1年:
SQL> alter table hr.departments flashback archive;
Table altered.
在创建新表时也能指定所使用的闪回数据归档:
SQL> create table oe.inventory
2 (id number,product_id number,supplier_id number) flashback archive fda1;
Table created.
使用“no flashback archive”子句可以关闭特定表上的闪回数据归档功能。执行该命令需要“flashback archive administer”系统权限:
SQL> alter table oe.inventory no flashback archive;
Table altered.
启用闪回数据归档之后大大扩展了闪回查询的时间窗口,比如在启用归档功能至少7个月之后再查看hr.employees表7个月前的内容:
SQL> select * from hr.employees
2 as of timestamp (systimestamp - interval ‘7‘ month);
以hr.employees基表为例,使用以下查询能够一睹闪回归档的主要信息:
SQL> select
2 a.flashback_archive_name fda_name,a.retention_in_days days,
3 ts.tablespace_name ts,ts.quota_in_mb,
4 t.archive_table_name
5 from
6 dba_flashback_archive a,
7 dba_flashback_archive_ts ts,
8 dba_flashback_archive_tables t
9 where
10 a.flashback_archive_name = ts.flashback_archive_name and
11 a.flashback_archive_name = t.flashback_archive_name and
12 t.owner_name = ‘HR‘ and
13 t.table_name = ‘EMPLOYEES‘;
FDA_NAME DAYS TS QUOTA_IN_M ARCHIVE_TABLE_NAME
---------- ---------- ------- ---------- --------------------
FDA1 365 USERS SYS_FBA_HIST_73953
其中ARCHIVE_TABLE_NAME字段的值就是归档中历史表的名字——SYS_FBA_ HIST_73953,该表不能直接查询,更不用提其他操作了。
此外结果中还显示了配额的大小(QUOTA_IN_MB)为空,即没有配额限制。管理员在创建闪回归档时实际上可以为其设置能够占用的磁盘空间上限,即所谓的配额。比如创建归档fda2时限制其空间限制为40GB:
SQL> create flashback archive fda2 tablespace users quota 40G retention 2 year;
Flashback archive created.
另外,闪回数据归档中的历史数据当然可以被手工清除。比如清除归档fda中一个月之前的数据:
SQL> alter flashback archive fda
2 purge before timestamp (systimestamp - interval ‘1‘ month);
Flashback archive altered.
或全部清除:
SQL> alter flashback archive fda purge all;
Flashback archive altered.
启用了闪回数据归档功能的表依然支持绝大多数的ddl命令。但在执行少数ddl命令时会遭遇“ORA-55610: Invalid DDL statement on history-tracked table”错误,比如“alter table … shrink space”、“alter table … move”、“alter table … exchange partition”等。接下来以“alter table … exchange partition”举例说明。以下分别是一张分区表和一张堆栈表的ddl定义:
分区表(范围类分区——By Range):
SQL> create table hr.rpt (id number,name varchar2(30))
2 partition by range (id)
3 (
4 partition p1 values less than (100) tablespace users,
5 partition p2 values less than (200) tablespace users,
6 partition p3 values less than (maxvalue) tablespace users
7 );
Table created.
堆栈表:
SQL> create table hr.source (id number, name varchar2(30)) tablespace users;
Table created.
使用“exchange partition”交换分区表里的名为“p3”的段与堆栈表名为“source”的段,在普通情况下当然没有问题:
SQL> alter table hr.rpt exchange partition p3 with table hr.source;
Table altered.
若是分区表有闪回数据归档支撑情况将有所不同,“exchange partition”子句不会执行。比如首先在分区表RPT上启用归档:
SQL> alter table hr.rpt flashback archive fda1;
Table altered.
再执行交换分区的命令就会换来ORA-55610错误:
SQL> alter table hr.rpt exchange partition p3 with table hr.source;
alter table hr.rpt exchange partition p3 with table hr.source
*
ERROR at line 1:
ORA-55610: Invalid DDL statement on history-tracked table
这样的ddl再也不能直接在使用归档的表上执行了。为了达到ddl命令的目的,Oracle提供一种临时将基表与历史表分离的措施,让基表(本例的RPT表)变为普通的没有打开归档功能的表,然后在RPT表上执行报ORA-55610错误的ddl命令,最后再重新关联基表(RPT表)。其中,实现分离和关联功能的是PL/SQL包dbms_flashback_archive。首先可以查看一下RPT历史表的名称:
SQL> select archive_table_name from dba_flashback_archive_tables
2 where owner_name=‘HR‘ and table_name=‘RPT‘;
ARCHIVE_TABLE_NAME
-----------------------------------------------------
SYS_FBA_HIST_74619
然后使用dbms_flashback_archive的disassiociate_fba过程将RPT表与其历史表(SYS_FBA_HIST_74619)切断联系,这样才能在这两张表上执行所有的ddl命令,并且,如果管理员愿意,还能在历史表上执行dml命令:
SQL> exec dbms_flashback_archive.disassociate_fba(‘HR‘,‘RPT‘);
PL/SQL procedure successfully completed.
执行之前报告ORA-55610错误的ddl命令,如今应该畅通无阻了:
SQL> alter table hr.rpt exchange partition p3 with table hr.source;
Table altered.
最后使用reassociate_fba过程将RPT表和历史表重新结合:
SQL> exec dbms_flashback_archive.reassociate_fba(‘HR‘,‘RPT‘);
PL/SQL procedure successfully completed.
凡是遭遇ORA-55610错误的ddl命令都可以这样处理。当然如果ddl命令更改了基表的字段结构,必须在执行reassociate_fba过程之前在历史表上也做出相应的修改。常用的ddl命令支持直接在基表上执行,如有必要Oracle会自动地将修改体现在历史表上,包括“alter table”命令的add、drop、rename、modify字段子句;“alter table”命令的add、drop、rename约束子句;“alter table”命令的drop、truncate分区子句;truncate命令和rename命令。