oracle的闪回很早就出来了,准确的说一直以来应该都较少被真正用户广为使用,除了dba和极少部分开发人员偶尔用于逻辑出错、误删恢复之外,较少被用于产生更有价值的用途。

各种闪回表flashback table、flashback query、flashback transaction都有一定的适用场景,但是他们称不上和其他特性比如分区、并行那么自然和普遍适用性,同时数据存储在撤销表空间,而撤销表空间的性能对系统影响极大,大量的undo保留着会使得更多的顺序读变成随机读。直到oracle 11g开始引入的Flashback Data Archive闪回数据归档,它原先属于 (Oracle Total Recall)选项的唯一功能,后来并合并到了advanced compression选项中,June 2013开始不专门收费。虽然11gR1就引入了闪回数据归档,可以说这个时候是适用于纯OLTP场景的,但是纯粹的OLTP其实帮助并不是很大,因为交易出错是正常的一部分,而且不管是否出错、对账都是标准的一部分,这可以通过应用解决。金融批处理的特性在于相对存量而言、增量不是很大,逻辑巨复杂、很可能经常会出现少数交易异常、某个环节异常需要重新计算,因为考虑到增量也可能突然会有成千上百万,所以我们会使用各种特性去提高性能,并行、分区、直接路径、nologging、truncate等等,对于多租户,增加分区也是可以的。

根据https://oracle-base.com/articles/11g/flashback-and-logminer-enhancements-11gr1以及官方资料,11gR2支持各常用ddl,起码truncate是支持的,实际测试下来11.2.0.1仍然是不支持的,升级到11.2.0.1之后才支持(测试用的版本是11.2.0.4可以支持),12cR1的增强User-Context Tracking,不能说完全没有意义,但是算是个鸡肋,因为涉及到逻辑正确性,基本不会有应用愿意依赖他,跟VPD差不多。

In addition, there are certain DDL restrictions associated with having flashback archiving enabled in 11gR1. The following operations result in a ORA-55610 error.

  • ALTER TABLE statements that drop, rename or modify columns.
  • ALTER TABLE statements that performs partition or subpartition operations.
  • ALTER TABLE statements that converts a LONG column to a LOB column.
  • ALTER TABLE statements that includes an UPGRADE TABLE clause, with or without an INCLUDING DATA clause.
  • DROP TABLE statements.
  • RENAME TABLE statements.
  • TRUNCATE TABLE statements.

In 11gR2 some of these restrictions have been removed and the following DDL is supported.

  • Add, drop, rename or modify column.
  • Drop or truncate partitions.
  • Rename or truncate tables.
  • Add, drop, rename or modify constraints.
  • More complex DDL can be performed in conjunction with the DISASSOCIATE_FBA and REASSOCIATE_FBA procedures of the DBMS_FLASHBACK_ARCHIVE package(比如说增加分区、删除分区).

对于存量基数大,增量相对小的处理来说,FDA可能是最合适的适用场景,他可以让我不用为每个环节创建那么多的备份,直接在FDA中保留指定时间指定表的undo(这应该算提供了最大的灵活性,直接就是create/alter table的一个选项,维护成本最小化),保留时间长度支持天、月、年,不支持小时以及更小单位(这并不总是合适,有时候为了节省空间,我们真的就不需要超过1天)。

再好的特性,如果限制太多或者和其他特性冲突太多,就没什么价值了,所以先看FDA的限制,截止11.2.0.4,默认不支持新增分区,但可以通过DBMS_FLASHBACK_ARCHIVE支持,同时仍然可以闪回查询。它的原理是有一个后台进程不停地异步读取UNDO,写到一个用于闪回归档的表空间,进而最小化对前台的影响,如下所示。

oracle闪回、闪回数据归档Flashback Data Archive (Oracle Total Recall)的真正强大之处、11gR2增强以及合理使用-LMLPHP

从测试来看,从几行到数十万每行6KB多记录的DELETE来看,确实前台没什么感知,但是truncate性能会下降,大数据量相当于执行了DELETE,空表truncate都在7秒多(根据sql_trace,因为维护后台SYS_FBA_TCRV_n所致,采用了NL循环,截止11.2.0.4所致)。

FDA还可以用来直接作为flashback table的源头,比如flashback table CUSTOMER1 to timestamp systimestamp - 30/1440;

再看下flashback table 物化视图的基表,会出现ORA-08194: Flashback Table operation is not allowed on materialized views,见How to flashback MVs and MV referred tables [ID 781112.1],这也不奇怪,因为flashback的原理是直接拿undo替换现在的数据块,而MV有些类似redo机制,这没法直接实现(哪怕让用户自己控制flashback mv避免重新全量也好刷新也好啊,起码目前没有,不过已经有内部的request https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9537333800346745966)。所以,如果用来物化视图,只能通过flashback query as of scn查到当时的快照,然后delete/insert自定义业务回滚。如果只有insert/update,这就比较简单了,使用ORA_ROWSCN机制进行撤销即可,但是如果有delete就只能参考前者自定义排查有哪些变更了(最好是通过逻辑删除标记来实现简化恢复)。其次,如果需要恢复部分数据,也不能直接用flashback table,只能用flashback query。

FDA总体来说,还是能够解决不少问题的。

假设要恢复部分增加、修改、删除,目标是避免备份 表、最小化恢复成本、最小化对空间的需求、undo不扩张、不影响现有物化视图,启用行依赖(用于支持truncate、add column、modify column)、启用FDA。测试场景如下:

场景1:

1、下午15:00开始运行

2、17:15 要恢复X托管人W产品的记录,有新增、修改、删除;

delele from pdt where where 托管人=X and 产品=W;  #删除当前的

insert into pdt select * from pdt as of timestamp = 15:00 where 托管人=X and 产品=W;  #恢复原来的

场景2(并行进行):

1、下午15:00开始运行

2、17:19 要恢复Y托管人的记录,有新增、修改、删除、truncate;

delele from pdt where where 托管人=Y  #删除当前的

insert into pdt select * from pdt as of timestamp = 15:00 where 托管人=Y  #恢复原来的

场景3(这种场景分情况:1、变更数据量占整个的比例较低,比如说1/4以下,直接删掉,insert性能就太低了,而且会严重影响物化视图刷新和redo生成

             2、比例较大,1/3以上,可以直接delete/insert

这里重点看第1种,没有物化视图的话,直接flashback table就可以了):

1、下午15:00开始运行

2、17:19 全部变更恢复到15:00,有新增、修改、删除、truncate;

select ora_rowscn,pk from pdt where ora_rowscn > 15:00的时间戳,新增、修改的都已经查出来(最好是限定必要的条件,如果表特别大、而变更相对比较少的话)

delete from pdt where pk = 第一步查出来的pk #此时,新增修改的全部删掉

insert into pdt select * from pdt as of timestamp = 15:00 where pk = 第一步查出来的pk  #新增、修改的全部恢复完成

期间删除的pk只能业务记录,通过触发器或者其他机制,这样就只有删除会额外增加成本,其他不受影响。

insert into pdt select * from pdt as of timestamp = 15:00 where pk = 业务记录的删除的pk

在此期间、物化视图同步正常进行、不受影响,undo大小不受影响,只要表空间足够、可恢复当前系统时间-24小时内任何时间点。其中X、Y、W开发人员需要自己知道上下文信息。

实现方式:

0、分区表归历史,历史的不动。

1、需要恢复的建表语句增加选项 flashback archive、ENABLE ROW MOVEMENT(如果可能DDL的话)、ROWDEPENDENCIES(需要满足场景3的话);

2、新增、修改分区改为:

begin
DBMS_FLASHBACK_ARCHIVE.DISASSOCIATE_FBA(user, 'CUSTOMER1');
end;
/ alter table CUSTOMER1 add partition CUS_PART7 VALUES LESS THAN (700000) ; begin
DBMS_FLASHBACK_ARCHIVE.REASSOCIATE_FBA(user, 'CUSTOMER1');
end;
/

3、需要恢复的点通过select dbms_flashback.get_system_change_number from dual;记录SCN。

上述模式理论上可行,可以简化不少开发并且提高系统运行性能。最近测试闪回的时候出现一个天坑,参见oracle flashback data archive闪回数据归档天坑之XID重用导致闪回查询数据重复,问题已解决,参见其。

FDA上的表还有一个限制,如下:

  if v_rowcount > 0 then
execute immediate 'create table ta_treliqcpdatatmp as select * from ta_tacconet';
execute immediate 'drop table ta_tacconet'; -- drop语句会suspend,查看v$session发现其在等待fbar timer事件
end if;

要使得drop立刻完成,需要禁用fda,如下:

execute immediate 'alter table ta_taccoinfo no flashback archive';
execute immediate 'drop table ta_taccoinfo';

这样就不会卡住了。

05-11 11:33