Flashback versions Query
相对于Flashback Query 只能看到某一点的对象状态, Oracle 10g引入的Flashback Version Query可以看到过去某个时间段内,记录是如何发生变化的。 根据这个历史,DBA就可以快速的判断数据是在什么时点发生了错误,进而恢复到之前的状态。我们来了解下伪列 . 所谓的伪列,就是假的,不存在的数据列,用户创建表时虽然没有指定,但是Oracle为了维护而添加的一些内部字段,这些字段可以像普通文件那样的使用。最熟悉的伪列就是 ROWID, 它相当于一个指针,指向记录在磁盘上的位置。ORA_ROWSCN 是Oracle 10g 新增的,暂且把它看作是记录最后一次被修改时的SCN。 Flashback Version Query 就是通过这个伪列来跟踪出记录的变化历史。
Flashback Versions between版本查询功能很强大,通过versions between能够查看指定时间段内undo表空间中记录的不同版本(注意,只包括被提交的记录)。
版本查询的用法并不比as of复杂,与其类似,你只需要在标准查询后面附加versions between timestamp[/scn] t1 and t2即可。记录在版本查询中可能会是一对多的关系,比如某些记录如果被修改过多次,并分别提交,那么你在查询的时候,如果修改的操作是在你指定的时间段(或scn),则记录每次修改的结果都会被选择出来,这比较有利于我们做数据的对比,比如看看数据究竟是怎么变化的。
Flashback versions Query具体的实验:
SQL> create table T(id int,name varchar2(30));
Table created.
SQL> select count(*) from T;
COUNT(*)
----------
0
下面做些DML,得到一些不同的数据信息
SQL> insert into T values(1,'Jack');
1 row created.
SQL> insert into T values(2,'John');
1 row created.
SQL> commit;
Commit complete.
SQL> insert into T values(3,'Watson');
1 row created.
SQL> commit;
Commit complete.
SQL> insert into T values(4,'Sam');
1 row created.
SQL> commit;
Commit complete.
SQL> update T set name='Samnor' where id=4;
1 row updated.
SQL> commit;
Commit complete.
SQL> insert into T values(5,'XXX');
1 row created.
SQL> commit;
Commit complete.
SQL> delete from T where id=5;
1 row deleted.
SQL> commit;
Commit complete.
查询T的信息
SQL> set linesize 180
SQL> select ora_rowscn, id,NAME from T;
ORA_ROWSCN ID NAME
---------- ---------- ------------------------------------------------------------
671761 1 Jack
671761 2 John
671761 3 Watson
671761 4 Samnor
查看更多的历史信息
SQL> Select versions_xid,versions_startscn,versions_endscn,DECODE(versions_operation,'I','Insert','U','Update','D','Delete', 'Original') "Operation",
id,name from T versions between scn minvalue and maxvalue;
VERSIONS_XID VERSIONS_STARTSCN VERSIONS_ENDSCN Operation ID NAME
---------------- ----------------- --------------- ---------------- ---------- ------------------------------------------------------------
07002E00EA000000 671761 Delete 5 XXX
0800250026010000 671755 671761 Insert 5 XXX
0600130013010000 671748 Update 4 Samnor
03001E0018010000 671733 671748 Insert 4 Sam
0500170029010000 671726 Insert 3 Watson
0A000900DB000000 671660 Insert 2 John
0A000900DB000000 671660 Insert 1 Jack
7 rows selected.
Flashback Version Query 技术其实有很多伪列,但是ORA_ROWSCN是最重要。它记录的是最后一次被修改时的SCN, 注意是被提交的修改。如果没有提交,这个伪列不会发生变化。ORA_ROWSCN 缺省是数据块级别的,也就是一个数据块内的所有记录都是一个ORA_ROWSCN,数据块内任意一条记录被修改,这个数据库块内的所有记录的ORA_ROWSCN都会同时改变。上例的查询结果以证明。他们的ORA_ROWSCN都是671761。因为他们是同一个块的。不过我们可以在建表时使用关键字rowdependencies, 可以改变这种缺省行为,使用这个关键字后,每条记录都有自己的ORA_ROWSCN。
Example:
SQL> create table T2(id int,name varchar2(30)) rowdependencies;
Table created.
SQL> insert into T2 values(1,'test1');
1 row created.
SQL> insert into T2 values(2,'test2');
1 row created.
SQL> insert into T2 values(3,'test3');
1 row created.
SQL> commit;
Commit complete.
SQL> select ora_rowscn, id,NAME from T2;
ORA_ROWSCN ID NAME
---------- ---------- ------------------------------------------------------------
673805 1 test1
673805 2 test2
673805 3 test3
此处SCN一样,因为他们是一起提交的,所以是SCN号一样,如果没有提交,是不会变的,我们重做一下DML--update,每条记录的SCN就不一样了。
SQL> update t2 set name='test11' where id=1;
1 row updated.
SQL> commit;
Commit complete.
SQL> select ora_rowscn, id,NAME from T2;
ORA_ROWSCN ID NAME
---------- ---------- ------------------------------------------------------------
673868 1 test11
673805 2 test2
673805 3 test3
SQL> update t2 set name='test22' where id=2;
1 row updated.
SQL> commit;
Commit complete.
SQL> select ora_rowscn, id,NAME from T2;
ORA_ROWSCN ID NAME
---------- ---------- ------------------------------------------------------------
673868 1 test11
673877 2 test22
673805 3 test3
SQL> update t2 set name='test33' where id=3;
1 row updated.
SQL> commit;
Commit complete.
SQL> select ora_rowscn, id,NAME from T2;
ORA_ROWSCN ID NAME
---------- ---------- ------------------------------------------------------------
673868 1 test11
673877 2 test22
673883 3 test33
结论:如果创建表时指定了rowdependencies,则ora_rowscn是以行为单位变化,而不是块
版本查询过程中提供了多个伪列如下:
VERSIONS_STARTSCN
VERSIONS_STARTTIME
该记录操作时的scn或时间,如果为空,表示该行记录是在查询范围外创建的。
VERSIONS_ENDSCN
VERSIONS_ENDTIME
该记录失效时的scn或时间,如果为空,说明记录当前时间在当前表内存在,或者已经被删除了,可以配合着VERSIONS_OPERATION列来看,如果VERSIONS_OPERATION列值为D,说明该列已被删除,如果该列为空,则说明记录在这段时间无操作。
VERSIONS_XID
该操作的事务ID
VERSIONS_OPERATION
对该行执行的操作:I表示insert,D表示delete,U表示update。
提示:对于索引键的update操作,版本查询可能会将其识别成两个操作:DELETE和INSERT。
在上述查询中,列 versions_starttime、versions_endtime、versions_xid、versions_operation 是伪列,与 ROWNUM、LEVEL 等其他熟悉的伪列相类似。其他伪列 如 VERSIONS_STARTSCN 和 VERSIONS_ENDSCN 显示了该时刻的系统更改号。列 versions_xid 显示了更改该行的事务标识符。有关该事务的更多详细信息可在视图 FLASHBACK_TRANSACTION_QUERY 中找到,其中列 XID 显示事务 id
Flashback versions query的几点注意:
1,表不能使用别名:如果在表名后面加上别名,则会报错。
SQL> select * from employees versions e between scn minvalue and maxvalue;
select * from employees versions e between scn minvalue and maxvalue
*
ERROR at line 1:
ORA-00933: SQL command not properly ended
2,伪列:如果使用伪列,则不能使用*来统配表中所有的字段,而应该用table_name.*:
SQL> select *,versions_xid from T versions between scn minvalue and maxvalue;
select *,versions_xid from T versions between scn minvalue and maxvalue
*
ERROR at line 1:
ORA-00923: FROM keyword not found where expected
3,如果要使用*来统配表中所有的字段,则必须在*前加上表名:
SQL> select T.*,versions_xid from T versions between scn minvalue and maxvalue;
ID NAME VERSIONS_XID
---------- ------------------------------------------------------------ ----------------
1 Jack11 0200270010010000
1 Jack1 01001B00DC000000
1 Jack
2 John
3 Watson
4 Samnor
6 rows selected.