Oracle9i提供的闪回特性增强,为数据恢复带来了极大的方便,但是Oracle9i的闪回查询只能提供某个时间点的数据视图,并不能告诉我们这样的数据经过了几个事务、怎样的修改(update,insert,delete等),而这些信息在回滚段中是存在的,在Oracle10g中,Oracle进一步加强了闪回查询的特性,提供了以下两种闪回查询:
闪回版本查询- Flashback Versions Query
闪回事务查询- Flashback Transaction Query
闪回版本查询允许使用一个新的VERSIONS子句查询两个时间点或者SCN之间的数据版本。这些版本可以按照事务进行区分,闪回版本查询只返回提交数据,未提交数据不被显示。
通过以下示例,来理解闪回版本查询的作用。首先创建一个测试表,执行一系列的DML操作:
SQL>create table t as select username,user_id from dba_users;
Table created.
SQL>select * from t;
USERNAME USER_ID
------------------------------ ----------
SYSTEM 5
SYS 0
TEST 25
EYGLE 26
SCOTT 29
DIP 19
TRANS 27
TEST1 28
OPERATOR 31
WMSYS 23
DBSNMP 22
OUTLN 11
12 rows selected.
SQL>delete from t where username='OUTLN';
1 row deleted.
SQL>commit;
Commit complete.
SQL>delete from t where username='TEST1';
1 row deleted.
SQL>commit;
Commit complete.
再执行一系列DML操作并提交:
SQL>update t set user_id=1 where username='EYGLE';
1 row updated.
SQL>commit;
Commit complete.
SQL>delete from t where user_id >10;
7 rows deleted.
SQL>commit;
Commit complete.
SQL>select * from t;
USERNAME USER_ID
------------------------------ ----------
SYSTEM 5
SYS 0
EYGLE 1
SQL>insert into t values('PENNY',2);
1 row created.
SQL>commit;
Commit complete.至此数据库中已经交替执行了多个事务,进行了众多的数据修改,现在的测试表已经与最初完全不同了。如果使用Oracle9i的闪回查询,是很难区分这些不同事务的变更,找到合适的、正确的数据将变得极为困难。
再来看看Oracle10g的闪回版本查询,通过使用versions子句和对数据表引入了一系列的伪列(version_starttime等),我们可以获得对数据表的所有事务操作,注意以下输出中versions_operation代表了不同类型的操作(D-Delete,I-Insert,U-Update), VERSIONS_XID是一个重要数据,代表了不同版本的事务ID:
SQL>select versions_starttime, versions_endtime, versions_xid, 2 versions_operation, username,user_id 3 from t versions between timestamp minvalue and maxvalue; VERSIONS_STARTTIME VERSIONS_ENDTIME VERSIONS_XID V USERNAME USER_ID ---------------------- ---------------------- ---------------- - ----------------- 30-MAR-05 09.34.49 AM 000A000B000000F1 D DBSNMP 22 30-MAR-05 09.34.49 AM 000A000B000000F1 D WMSYS 23 30-MAR-05 09.34.49 AM 000A000B000000F1 D OPERATOR 31 30-MAR-05 09.34.49 AM 000A000B000000F1 D TRANS 27 30-MAR-05 09.34.49 AM 000A000B000000F1 D DIP 19 30-MAR-05 09.34.49 AM 000A000B000000F1 D SCOTT 29 30-MAR-05 09.34.49 AM 000A000B000000F1 D TEST 25 30-MAR-05 09.34.15 AM 0001001900000F0F U EYGLE 1 30-MAR-05 09.33.51 AM 00080016000000EF D TEST1 28 30-MAR-05 09.33.23 AM 0004000A000005EF D OUTLN 11 SYSTEM 5 SYS 0 30-MAR-05 09.34.49 AM TEST 25 30-MAR-05 09.34.15 AM EYGLE 26 30-MAR-05 09.34.49 AM SCOTT 29 30-MAR-05 09.34.49 AM DIP 19 30-MAR-05 09.34.49 AM TRANS 27 30-MAR-05 09.33.51 AM TEST1 28 30-MAR-05 09.34.49 AM OPERATOR 31 30-MAR-05 09.34.49 AM WMSYS 23 30-MAR-05 09.34.49 AM DBSNMP 22 30-MAR-05 09.33.23 AM OUTLN 11 30-MAR-05 09.49.24 AM 00080006000000EF I PENNY 2 23 rows selected.
通过以上输出,我们根据VERSIONS_XID可以清晰地区分不同事务在不同时间对数据所作的更改。具备了flashback version query查询的基础,就可以进行基于flashback version query的事务级恢复,这就是flashback transaction query。
flashback transaction query可以从FLASHBACK_TRANSACTION_QUERY视图中获得指定事务的历史信息以及Undo_SQL,通过这个UNDO_SQL,我们就可以撤销特定的提交事务。
Flashback transaction query需要用到FLASHBACK_TRANSACTION_QUERY视图,我们先看一下视图
SQL> desc FLASHBACK_TRANSACTION_QUERY; Name Type Nullable Default Comments ---------------- -------------- -------- ------- -------------------------- XID RAW(8) Y Transaction identifier START_SCN NUMBER Y Transaction start SCN START_TIMESTAMP DATE Y Transaction start timestamp COMMIT_SCN NUMBER Y Transaction commit SCN COMMIT_TIMESTAMP DATE Y Transaction commit timestamp LOGON_USER VARCHAR2(30) Y Logon user for transaction UNDO_CHANGE# NUMBER Y 1-based undo change number OPERATION VARCHAR2(32) Y forward operation for this undo TABLE_NAME VARCHAR2(256) Y table name to which this undo applies TABLE_OWNER VARCHAR2(32) Y owner of table to which this undo applies ROW_ID VARCHAR2(19) Y rowid to which this undo applies UNDO_SQL VARCHAR2(4000) Y SQL corresponding to this undo
该视图的定义为:
select xid, start_scn, start_timestamp, decode(commit_scn, 0, commit_scn, 281474976710655, NULL, commit_scn) commit_scn, commit_timestamp, logon_user, undo_change#, operation, table_name, table_owner, row_id, undo_sql from sys.x$ktuqqry
继续前面的测试,如果需要撤销XID=000A000B000000F1的事务,可以通过如下步骤进行(注意当查询FLASHBACK_TRANSACTION_QUERY视图时如果直接引用XID则查询会因为无法使用索引而极其耗时):
SQL>set autotrace on
SQL>SELECT UNDO_SQL FROM FLASHBACK_TRANSACTION_QUERY
2 WHERE XID = '000A000B000000F1';
UNDO_SQL
--------------------------------------------------------------------------------
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('DBSNMP','22');
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('WMSYS','23');
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('OPERATOR','31');
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('TRANS','27');
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('DIP','19');
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('SCOTT','29');
insert into "EYGLE"."T"("USERNAME","USER_ID") values ('TEST','25');
8 rows selected.
Elapsed: 00:05:55.30
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=25 Card=1 Bytes=2008)
1 0 FIXED TABLE (FULL) OF 'X$KTUQQRY' (TABLE (FIXED)) (Cost=25 Card=1 Bytes=2008)
Statistics
----------------------------------------------------------
393454 recursive calls
0 db block gets
1562425 consistent gets
4644 physical reads
0 redo size
1069 bytes sent via SQL*Net to client
664 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
23166 sorts (memory)
0 sorts (disk)
8 rows processed此时可以通过hextoraw转换利用底层索引,提高查询速度:
SQL> set autotrace trace explain
SQL> SELECT UNDO_SQL FROM FLASHBACK_TRANSACTION_QUERY
2 WHERE XID = hextoraw('09000D00A3080000');
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 1747778896
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2008 | 0 (0)| 00:00:01 |
|* 1 | FIXED TABLE FIXED INDEX| X$KTUQQRY (ind:1) | 1 | 2008 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("XID"=HEXTORAW('09000D00A3080000') )
通过执行相应的UNDO语句我们可以撤销该事务,通过这些新特性,Oracle为我们提供了一种“回滚”提交事务的手段,极大的方便了我们应对不同情况的数据库恢复。




