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
andREASSOCIATE_FBA
procedures of the DBMS_FLASHBACK_ARCHIVE package(比如说增加分区、删除分区).
对于存量基数大,增量相对小的处理来说,FDA可能是最合适的适用场景,他可以让我不用为每个环节创建那么多的备份,直接在FDA中保留指定时间指定表的undo(这应该算提供了最大的灵活性,直接就是create/alter table的一个选项,维护成本最小化),保留时间长度支持天、月、年,不支持小时以及更小单位(这并不总是合适,有时候为了节省空间,我们真的就不需要超过1天)。
再好的特性,如果限制太多或者和其他特性冲突太多,就没什么价值了,所以先看FDA的限制,截止11.2.0.4,默认不支持新增分区,但可以通过DBMS_FLASHBACK_ARCHIVE支持,同时仍然可以闪回查询。它的原理是有一个后台进程不停地异步读取UNDO,写到一个用于闪回归档的表空间,进而最小化对前台的影响,如下所示。
从测试来看,从几行到数十万每行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';
这样就不会卡住了。