Oracle Flashback技术总结(三)—— Flashback Query

三、FlashbackQuery


Flashback是ORACLE自9i就开始提供的一项特性,在9i中利用oracle查询多版本一致的特点,实现从回滚段中读取表一定时间内操作过的数据,可用来进行数据比对,或者修正意外提交造成的错误数据,该项特性也被称为FlashbackQuery。


1、FlashbackQuery概念

正如前言中所提,FlashbackQuery是利用多版本读一致性的特性从UNDO表空间读取操作前的记录数据!

什么是多版本读一致性

Oracle采用了一种非常优秀的设计,通过undo数据来确保写不堵塞读,简单的讲,不同的事务在写数据时,会将数据的前映像写入undo表空间,这样如果同时有其它事务查询该表数据,则可以通过undo表空间中数据的前映像来构造所需的完整记录集,而不需要等待写入的事务提交或回滚。

flashbackquery有多种方式构建查询记录集,记录集的选择范围可以基于时间或基于scn,甚至可以同时查询出记录在undo表空间中不同事务时的前映象。用法与标准查询非常类似,要通过flashbackquery查询undo中的撤销数据,最简单的方式只需要在标准查询语句的表名后面跟上asof

timestamp(基于时间)或asofscn(基于scn)即可。asoftimestamp|scn的语法是自9iR2后才开始提供支持


2、Flashback Query的示例

Asoftimestamp的示例:

SYS@ orcl >alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

SYS@ orcl >select sysdate from dual;

SYSDATE

-------------------

2013-05-23 01:14:45


SYS@ orcl >select * from test014;

ID

----------

1

2

模拟用户误操作,删除数据

SYS@ orcl >delete from test014;

2 rows deleted.

SYS@ orcl >commit;

Commit complete.



查看删除之前的状态:

oracle 11g不需要等5分钟,9i/10g需要等5分钟

SYS@ orcl >select * from test014 as of timestamp sysdate-5/1440;

ID

----------

1

2

或者:

SYS@ orcl >select * from test014 as of timestamp to_timestamp('2013-05-23 01:14:45','yyyy-mm-dd hh24:mi:ss');

ID

----------

1

2

4


用FlashbackQuery恢复之前的数据:

SYS@ orcl >insert into test014 select * from test014 as of timestamp to_timestamp('2013-05-23 01:14:45','yyyy-mm-dd hh24:mi:ss');

2 rows created.


SYS@ orcl >select * from test014;

ID

----------

1

2


如上述示例中所表示的,asoftimestamp的确非常易用,但是在某些情况下,我们建议使用asofscn的方式执行flashbackquery,比如需要对多个相互有主外键约束的表进行恢复时,如果使用asoftimestamp的方式,可能会由于时间点不统一的缘故造成数据选择或插入失败,通过scn方式则能够确保记录的约束一致性。


Asofscn示例

查看SCN:

SELECTdbms_flashback.get_system_change_numberFROMdual;

SELECTCURRENT_SCNFROMV$DATABASE;


SYS@ orcl >select current_scn from v$database;

CURRENT_SCN

-----------

1825435


删除数据:

SYS@ orcl >delete from test014;

1 rows deleted.


SYS@ orcl >commit;

Commit complete.


查看删除之前的状态:获取scn值请参考[FlashbackversionQuery]

SYS@ orcl >select * from test014 as of scn 1825516;


ID

----------

5

用FlashbackQuery恢复之前的数据:

SYS@ orcl >insert into test014 select * from test014 as of scn 1825516;

1 row created.


SYS@ orcl >commit;

Commit complete.


SYS@ orcl >select * from test014;

ID

----------

5

事实上,Oracle在内部都是使用scn,即使你指定的是asoftimestamp,oracle也会将其转换成scn,系统时间标记与scn之间存在一张表,即SYS下的SMON_SCN_TIME


SYS@ orcl >desc sys.smon_scn_time;

Name Null? Type

----------------------- -------- ----------------

THREAD NUMBER

TIME_MP NUMBER

IME_DP DATE

SCN_WRP NUMBER

SCN_BAS NUMBER

NUM_MAPPINGS NUMBER

TIM_SCN_MAP RAW(1200)

SCN NUMBER

ORIG_THREAD NUMBER


每隔5分钟(oracle 11g没有5分钟限制,10g有这个限制),系统产生一次系统时间标记与scn的匹配并存入sys.smon_scn_time表,该表中记录了最近1440个系统时间标记与scn的匹配记录,由于该表只维护了最近的1440条记录,因此如果使用asoftimestamp的方式则只能flashback最近5天内的数据(假设系统是在持续不断运行并无中断或关机重启之类操作的话)。

注意理解系统时间标记与scn的每5分钟匹配一次这句话,举个例子,比如scn:339988,339989分别匹配08-05-3013:52:00和2008-13:57:00,则当你通过asoftimestamp查询08-05-3013:52:00或08-05-3013:56:59这段时间点

内的时间时,oracle都会将其匹配为scn:339988到undo表空间中查找,也就说在这个时间内,不管你指定的时间点是什么,查询返回的都将是08-05-3013:52:00这个时刻的数据。

查看SCN和timestamp之间的对应关系:

SYS@ orcl >select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss') time from sys.smon_scn_time

SCN TIME

---------- ------------------

832740 2011-02-17 12:51:28

833372 2011-02-17 12:57:47

833436 2011-02-17 12:58:22


四、FlashbackversionQuery


1、Flash version query概念

相对于FlashbackQuery只能看到某一点的对象状态,Oracle10g引入的FlashbackVersionQuery可以看到过去某个时间段内,记录是如何发生变化的。根据这个历史,DBA就可以快速的判断数据是在什么时点发生了错误,进而恢复到之前的状态。

先看一个伪列ORA_ROWSCN.所谓的伪列,就是假的,不存在的数据列,用户创建表时虽然没有指定,但是Oracle为了维护而添加的一些内部字段,这些字段可以像普通文件那样的使用。 最熟悉的伪列就是ROWID,它相当于一个指针,指向记录在磁盘上的位置。ORA_ROWSCN是Oracle10g新增的,暂且把它看作是记录最后一次被修改时的SCN。FlashbackVersionQuery就是通过这个伪列来跟踪出记录的变化历史。


例如:

SYS@ orcl >insert into test014(id) values(3)

SYS@ orcl >commit;

SYS@ orcl >select ora_rowscn,id from test014;

ORA_ROWSCN ID

---------- ----------

1893607 1

1893607 3


2、获取更多的历史信息

SYS@ orcl>select versions_xid,versions_starttime,versions_endtime,

versions_startscn,versions_endscn,versions_operation,id

from test014versions between scn minvalue and maxvalue


VERSIONS_XID VERSIONS_STARTTIME VERSIONS_ENDTIME VERSIONS_STARTSCN VERSIONS_ENDSCN V ID

------------------------- ------------------------- ------------------------- ----------------- --------------- - ----------

0100010089030000 23-MAY-13 11.37.07 PM 1916937 D 3

0100010089030000 23-MAY-13 11.37.07 PM 1916937 D 1

23-MAY-13 11.37.07 PM 1916937 1

23-MAY-13 11.37.07 PM 1916937 3


Table 13-1 Oracle Flashback Version Query Row Data Pseudocolumns

Pseudocolumn NameDescription

VERSIONS_STARTSCN

VERSIONS_STARTTIME

Starting System Change Number (SCN) orTIMESTAMPwhen the row version was created. This pseudocolumn identifies the time when the data first had the values reflected in the row version. Use this pseudocolumn to identify the past target time for Oracle Flashback Table or Oracle Flashback Query.

If this pseudocolumn isNULL, then the row version was created beforestart.

VERSIONS_ENDSCN

VERSIONS_ENDTIME

SCN orTIMESTAMPwhen the row version expired.

If this pseudocolumn isNULL, then either the row version was current at the time of the query or the row corresponds to aDELETEoperation.

VERSIONS_XID

Identifier of the transaction that created the row version.

VERSIONS_OPERATION

Operation performed by the transaction:Ifor insertion,Dfor deletion, orUfor update. The version is that of the row that was inserted, deleted, or updated; that is, the row after anINSERToperation, the row before aDELETEoperation, or the row affected by anUPDATEoperation.

For user updates of an index key, Oracle Flashback Version Query might treat anUPDATEoperation as two operations,DELETEplusINSERT, represented as two version rows with aDfollowed by anIVERSIONS_OPERATION.


3.ora_rowscn简介

下面我们来讲下伪列,FlashbackVersionQuery技术其实有很多伪列,但是ORA_ROWSCN是最重要。

它记录的是最后一次被修改时的SCN,注意是被提交的修改。如果没有提交,这个伪列不会发生变化。 ORA_ROWSCN缺省是数据块级别的,也就是一个数据块内的所有记录都是一个ORA_ROWSCN,数据块内任意一条记录被修改,这个数据库块内的所有记录的ORA_ROWSCN都会同时改变。上例的查询结果以证明。 不过我们可以在建表时使用关键字rowdependencies,可以改变这种缺省行为,使用这个关键字后,每条记录都有自己的ORA_ROWSCN。 另外 最后一次被修改时的SCN,如果没有提交,是不会变的,我们重做一下就清楚了。

举例:

SYS@ orcl>select ora_rowscn,id from test014;


ORA_ROWSCN ID

---------- ----------

1922994 1


 
 

为了更好的让读者理解ora_rowscn本质:特别引用【作者:江枫 阿里巴巴数据库集团团http://www.taobaodba.com/html/243_about_ora_rowscn.html

Oracle10g引入了一个新的ORA_ROWSCN的伪列,可以查询表中记录最后变更的SCN。这个新的伪列在某些环境下会非常有用,比如执行乐观锁定,或者增量数据抽取的时候。但是,默认情况下,每行记录的ORA_ROWSCN是基于Block的,除非在建表的时候执行开启行级跟踪(create table … rowdependencies)。

先来简单理解一下ORA_ROWSCN的实现原理。我们知道,每个Block在头部是记录了该block最近事务的SCN的,所以默认情况下,只需要从block头部直接获取这个值就可以了,不需要其他任何的开销,Oracle就能做到这一点。但是这明显是不精确的,一个block中会有很多行记录,每次事务不可能影响到整个block中所有的行,所以这是一个非常不精准的估算值,同一个block的所有记录的ORA_ROWSCN都会是相同的,基本上没有多大的使用价值。

如果在建表的时候开启行级跟踪选项,Oracle则可以为每一行记录精确的SCN,那么显然不能再直接从block头部获取。要获得足够的信息,肯定要付出一定的代价,Oracle必须为每一行实际的存储这个SCN。所以这个行级跟踪的选项,只能在建表的时候指定,而不能通过alter table来修改现有的表,否则需要修改每一行记录的物理存储格式,代价是可想而知的。

简单的做个实验就可以知道开启行级跟踪以后块记录格式的不同。建两个表,一个norowdependencies(默认),一个rowdependencies,然后分别dump出相应的数据块:

create table t1(i int);
insert into t1 values(1);
insert into t1 values(2);
commit;
create table t2 rowdependencies as select * from t1;
norowdependencies :

block_row_dump:
tab 0, row 0, @0x1f9a
tl:6fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 2] c1 02
tab 0, row 1, @0x1f94
tl:6fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 2] c1 03
end_of_block_dump

rowdependencies

block_row_dump:
tab 0, row 0, @0x1f7c
tl:12fb: –H-FL– lb: 0×0 cc: 1
dscn 0×0000.00029ae4
col 0: [ 2] c1 02
tab 0, row 1, @0x1f6d
tl:12fb: –H-FL– lb: 0×0 cc: 1
dscn 0×0000.00029ae4
col 0: [ 2] c1 03
end_of_block_dump

得到行的SCN后,通过SCN_TO_TIMESTAMP函数可以转化为时间:

SQL>  select SCN_TO_TIMESTAMP(ora_rowscn) from t2 where rownum

乐观锁和ORA_ROWSCN
需要select … for update做悲观锁定的时候,通过使用ORA_ROWSCN可以改成乐观锁定。一开始select数据的时候将ORA_ROWSCN查出来,修改后如果要写回数据库之前再比对下最新的ORA_ROWSCN就可以知道这期间数据是否有发生变化。这个Tom在他的大著《Expert Oracle Database Architecture 9i and 10g Programming Techniques and Solutions 》中也是有提到的。

增量数据抽取和ORA_ROWSCN
每次抽取后记录最大的ORA_ROWSCN,下次抽取再基于上一次的SCN来获得最近修改过的数据即可。在10g之前,很多系统要实现增量数据抽取,要么通过解析日志,要么加触发器,要么就在表上加一个时间截字段。ORA_ROWSCN其实就是第三种方式,只是这个字段由Oracle来维护,这样可以避免一些应用绕过时间截去更新其他字段带来的问题。不过,如果系统中使用了逻辑备库或者streams等逻辑复制的方案,而数据抽取又是基于逻辑备库的话,ORA_ROWSCN就可能对抽取后的数据分析有影响了,因为通过这个得到的时间是逻辑备库上记录变更的时间,而不是源库的时间了。当然,如果纯粹只是做数据抽取,而不需要使用这个时间来做分析,还是问题不大的,但还是要考虑一旦逻辑备库出现故障需要重做的,则这个增量抽取要怎么来处理的问题。

Metalink上搜一下ORA_ROWSCN可以看到不少相关的bug,所以在生产系统中使用的时候要小心。例如,我在Linux64平台上的一台测试库中,执行以下语句就会碰到ORA-07445的错误:

SQL> select ora_rowscn from x$bh where rownum



五、FlashbackTransactionQuery

FlashbackTransactionQuery也是使用UNDO信息来实现。利用这个功能可以查看某个事务执行的所有变化,它需要访问flashback_transaction_query视图,这个视图的XID列代表事务ID,利用这个ID可以区分特定事务发生的所有数据变化。在Oracle Database 11g中,需要启用supplemental log data才能够得到UNDO SQL。

SYS@ orcl>alter database add supplemental log data;

示例:

SYS@ orcl>delete from test014

SYS@ orcl>commit;


查看视图,每个事务都对应相同的XID

SYS@ orcl>select xid,commit_scn,operation,undo_sql

from flashback_transaction_query

where xid in (select versions_xid from test014 versions between scn minvalue and maxvalue)


XID COMMIT_SCN OPERATION UNDO_SQL

---------------- ---------- ---------- ------------------------------------------------------------

07001200AB030000 1935325 DELETE insert into "SYS"."TEST014"("ID") values ('2');

07001200AB030000 1935325 BEGIN

020005006B040000 1928700 UNKNOWN

020005006B040000 1928700 BEGIN

0A00010099030000 1922994 UNKNOWN

0A00010099030000 1922994 BEGIN

09001C0080040000 1935320 INSERT delete from "SYS"."TEST014" where ROWID = 'AAASk0AAEAAAAJHAAA';


此处的UNDO_SQL显示为两行,其中一条为BEGIN,这是作为事务开始的标记。Oracle隐式的开始一个事务,在Reverse转换时,BEGIN被显示出来,而且在INSERT之后:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值