暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

about flashback_transaction_query

原创 Roger 2013-07-01
736
前几天某大师提醒我说了,我以前一篇文档flashback_transaction_query 查询慢的问题 有点问题。 现在回想一下,确实不太对,
虽然以前的方法也是一种处理方法然而有点偏离方向了。首先我们来看一下试图的定义:
---definition

CREATE OR REPLACE FORCE VIEW "SYS"."FLASHBACK_TRANSACTION_QUERY" ("XID", "STAR
T_SCN", "START_TIMESTAMP", "COMMIT_SCN", "COMMIT_TIMESTAMP", "LOGON_USER", "UNDO
_CHANGE#", "OPERATION", "TABLE_NAME", "TABLE_OWNER", "ROW_ID", "UNDO_SQL") AS
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

可以看到,该试图的本质是访问x$ktuqqry. 那么这个试图是干什么的呢?显然是闪回事务查询的时候需要用到的东西,而且访问的
的数据是来自undo.下面我们随便从该试图中取一个xid来重现一下:

SQL> select xid from FLASHBACK_TRANSACTION_QUERY where rownum < 2;

XID
----------------
0C0012008F030000

SQL> select count(1) from FLASHBACK_TRANSACTION_QUERY where xid='0C0012008F030000';
select count(1) from FLASHBACK_TRANSACTION_QUERY where xid='0C0012008F030000'
*
ERROR at line 1:
ORA-01013: user requested cancel of current operation

Elapsed: 00:01:14.06


可以发现访问很慢,为什么呢 ?我们先来看下执行计划:


SQL> set autot traceonly exp
SQL> select count(1) from FLASHBACK_TRANSACTION_QUERY where xid='0C0012008F030000';
Elapsed: 00:00:00.02

Execution Plan
----------------------------------------------------------
Plan hash value: 3839279163

-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost ({39ecd679003247f2ed728ad9c7ed019a369dd84d0731b449c26bf628d3c1a20b}CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 0 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | FIXED TABLE FULL| X$KTUQQRY | 1 | 9 | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter(RAWTOHEX("XID")='0C0012008F030000')

SQL> set autot off

可以发现,id 2的地方走了table full scan,也就是全表扫描. 以前没用注意的一个细节.大家注意看下面的filter部分,很明显是
进行了隐式转换,以至于走full table scan了。 这里用的rwatohex进行了转换,那么如果使用hextoraw进行反向转一下呢 ?

SQL> select count(1) from FLASHBACK_TRANSACTION_QUERY where xid=hextoraw('0C0012008F030000');

COUNT(1)
----------
8

Elapsed: 00:00:00.01
SQL> set autot on
SQL> select count(1) from FLASHBACK_TRANSACTION_QUERY where xid=hextoraw('0C0012008F030000');

COUNT(1)
----------
8

Elapsed: 00:00:00.02

Execution Plan
----------------------------------------------------------
Plan hash value: 728944840

----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost ({39ecd679003247f2ed728ad9c7ed019a369dd84d0731b449c26bf628d3c1a20b}CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 0 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | FIXED TABLE FIXED INDEX| X$KTUQQRY (ind:1) | 1 | 9 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("XID"=HEXTORAW('0C0012008F030000') )

Statistics
----------------------------------------------------------
25 recursive calls
0 db block gets
51 consistent gets
0 physical reads
0 redo size
411 bytes sent via SQL*Net to client
400 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
1 rows processed


可以发现,这样的话,速度非常之快. 原来以前一直犯了一个错误,误导了不少人啊. 自我批评下.

到这里可能很多人以为这篇文章到此结束了,是吗? 实际上,故事才刚刚开始....

或许有些网友已经想到了,这个试图是干吗的?闪回查询,那么如何去定位到这个xid号呢 ?

假如1分钟之前某人删除了一条记录,那么我们要通过闪回事务去恢复这条数据,如何去进行恢复呢 ? 我们可以直接通过
查询该试图来获取undo_sql 进行恢复,其关键是如何获得该操作的XID ?

+++++++++ 方法1 闪回查询 +++++++++

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

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2013-06-30 04:52:48

SQL> select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss')from sys.smon_scn_time
2 where to_char(time_dp,'yyyy-mm-dd hh24:mi:ss') > '2013-06-30 04:40:00' order by 2;

SCN TO_CHAR(TIME_DP,'YY
---------- -------------------
8560772 2013-06-30 04:44:56

SQL> select current_scn from v$database;

CURRENT_SCN
-----------
8561007

SQL> col versions_starttime for a35
SQL> col versions_endtime for a35
SQL> select * from (
2 select versions_starttime, versions_endtime, versions_xid, versions_operation,object_id
3 from roger.test_undo1 versions between timestamp minvalue and maxvalue order by 5 desc) where rownum < 5;

VERSIONS_STARTTIME VERSIONS_ENDTIME VERSIONS_XID V OBJECT_ID
----------------------------------- ----------------------------------- ---------------- - ----------
30-JUN-13 04.23.43 AM 0C0012008F030000 D 1051
24-JUN-13 06.25.10 AM 30-JUN-13 04.23.43 AM 15000C0084030000 I 1051
1050
1049

这里的versions_xid,就表示该事务的xid,其中versions_operaition表示操作类型:D表示delete,I表示insert,U表示update.
通过该xid,我们可以直接查询undo_sql,然后执行该sql文本就可以将该条删除的数据恢复回来,如下查询:
 
SQL> select undo_sql from FLASHBACK_TRANSACTION_QUERY
2 where xid=hextoraw('0C0012008F030000');

UNDO_SQL
--------------------------------------------------------------------------------------------------------------------------
/* No SQL_UNDO for temporary tables */
/* No SQL_UNDO for temporary tables */
/* No SQL_UNDO for temporary tables */
delete from "SYS"."PLAN_TABLE$" where ROWID = 'AAQAIJAABAAAAIKAAC';
delete from "SYS"."PLAN_TABLE$" where ROWID = 'AAQAIJAABAAAAIKAAB';
delete from "SYS"."PLAN_TABLE$" where ROWID = 'AAQAIJAABAAAAIKAAA';
insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATE
D","LAST_DDL_TIME","TIMESTAMP","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('PUBLIC','V$_LOCK',NULL,'1051',NULL,'
SYNONYM',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DATE('15-APR-10', 'DD-MON-RR'),'2010-04-15:13:15:01','VALID','N','N','N');


实际上我们利用该视图来定位undo_sql,关键的地方是定位到具体的xid。

那么针对一个表的操作,可能有很多,我们如何去定位呢? 其实完全可以结合scn和operation以及table_name,table_owner来缩小范围.
类似如下的操作:
SQL> select XID,OPERATION,UNDO_CHANGE#,TABLE_NAME,TABLE_OWNER,ROW_ID
2 from FLASHBACK_TRANSACTION_QUERY where table_name='TEST_UNDO1' and table_owner='ROGER' and row_id >'AAAPJyAACAAAR/vABN';

当然如果由于该x$表仅仅在xid字段上存在索引,索引这样查询,可能会比较慢.如下:

SQL> l
1 select XID,OPERATION,UNDO_CHANGE#,TABLE_NAME,TABLE_OWNER,ROW_ID
2* from FLASHBACK_TRANSACTION_QUERY where table_name='TEST_UNDO1' and table_owner='ROGER' and row_id >'AAAPJyAACAAAR/vABN'
SQL> /

XID OPERATION UNDO_CHANGE# TABLE_NAME TABLE_OWNE ROW_ID
---------------- -------------------------------- ------------ ---------- ---------- -------------------
0C0012008F030000 DELETE 7 TEST_UNDO1 ROGER AAAPJyAACAAAR/wAAA
140013009C030000 DELETE 1 TEST_UNDO1 ROGER AAAPJyAACAAAR/vABO
15000C0084030000 INSERT 1 TEST_UNDO1 ROGER AAAPJyAACAAAR/wAAA

Elapsed: 00:02:10.59

显然这里我们根据判断知道第1条信息是我们所需要的.



++++++++++ 方法2 根据rowid 边界定位xid ++++++++++

除了利用闪回的方法,是否还有其他方法呢?假如我删除掉一个范围的数据,例如:

--Session 1
SQL> show user
USER is "ROGER"
SQL> delete from test_undo1 where object_id > 300 and object_id < 400;

90 rows deleted.

SQL> commit;

Commit complete.

不考虑边界的问题,某条数据通常会跟其他数据存在同一block中,所以根据删除的数据范围,定位到block 号:

SQL> select rowid,
2 dbms_rowid.rowid_object(rowid) object_id,
3 dbms_rowid.rowid_relative_fno(rowid) file_id,
4 dbms_rowid.rowid_block_number(rowid) block_id,
5 dbms_rowid.rowid_row_number(rowid) num,
6 rowidtochar(rowid)
7 from roger.test_undo1 where object_id=300;

ROWID OBJECT_ID FILE_ID BLOCK_ID NUM ROWIDTOCHAR(ROWID)
------------------ ---------- ---------- ---------- ---------- ------------------
AAAPJyAACAAAR/nAAV 62066 2 73703 21 AAAPJyAACAAAR/nAAV

Elapsed: 00:00:00.01
SQL> select rowid,
2 dbms_rowid.rowid_object(rowid) object_id,
3 dbms_rowid.rowid_relative_fno(rowid) file_id,
4 dbms_rowid.rowid_block_number(rowid) block_id,
5 dbms_rowid.rowid_row_number(rowid) num,
6 rowidtochar(rowid)
7 from roger.test_undo1 where object_id=400;

ROWID OBJECT_ID FILE_ID BLOCK_ID NUM ROWIDTOCHAR(ROWID)
------------------ ---------- ---------- ---------- ---------- ------------------
AAAPJyAACAAAR/oAAd 62066 2 73704 29 AAAPJyAACAAAR/oAAd

Elapsed: 00:00:00.02
SQL>

---Session 2
SQL> conn /as sysdba
Connected.
SQL> oradebug setmypid
Statement processed.
SQL> alter system dump datafile 2 block 73703
2 /

System altered.

SQL> alter system dump datafile 2 block 73704;

System altered.

SQL> oradebug close_trace
Statement processed.
SQL> oradebug tracefile_name
/home/ora10g/admin/roger/udump/roger_ora_14279.trc

此时roger_ora_14279.trc 内容如下:


Block header dump: 0x00811fe7
Object id on Block? Y
seg/obj: 0xf272 csc: 0x00.7f0cc2 itc: 3 flg: E typ: 1 - DATA
brn: 0 bdba: 0x811fe1 ver: 0x01 opc: 0
inc: 0 exflg: 0

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.007f0cc2
0x02 0x000c.011.0000038f 0x0180608c.0734.02 --U- 61 fsc 0x1388.00837f8d
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

data_block_dump,data header at 0xd0da87c
===============
tsiz: 0x1f80
hsiz: 0xb8
pbl: 0x0d0da87c
bdba: 0x00811fe7
76543210

.........
Block header dump: 0x00811fe8
Object id on Block? Y
seg/obj: 0xf272 csc: 0x00.7f0cc2 itc: 3 flg: E typ: 1 - DATA
brn: 0 bdba: 0x811fe1 ver: 0x01 opc: 0
inc: 0 exflg: 0

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.007f0cc2
0x02 0x000c.011.0000038f 0x0180608c.0734.1f --U- 29 fsc 0x08de.00837f8d
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

data_block_dump,data header at 0xd0da87c
===============
tsiz: 0x1f80
hsiz: 0xc0
pbl: 0x0d0da87c
bdba: 0x00811fe8
76543210
......

从上面2个block的dump可以看出xid 信息如下:
0x000c.011.0000038f
0x000c.011.0000038f 虽然涉及到多个block的操作,但是仍然是同一个事务.所以这里xid的一个值.

将其转换为FLASHBACK_TRANSACTION_QUERY.xid的格式,其长度为16位,不足的部分用0补齐.

0c00 1100 8f030000 即使xid=0c0011008f030000

获取到xid后,直接生成恢复的脚本即可,如下:

SQL> set pagesize 5000
SQL> col undo_sql for a150
SQL> set long 9999999
SQL> spool test_undo1_insert.sql
SQL> select undo_sql from FLASHBACK_TRANSACTION_QUERY where xid=hextoraw('0c0011008f030000');

UNDO_SQL
------------------------------------------------------------------------------------------------------------------------------------------------------
insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('SYS','SUMDETAIL$',NULL,'399','399','TABLE',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DATE('15-APR
-10', 'DD-MON-RR'),'2010-04-15:13:14:46','VALID','N','N','N');

insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('SYS','I_SUM$_1',NULL,'398','398','INDEX',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DATE('15-APR-1
0', 'DD-MON-RR'),'2010-04-15:13:14:46','VALID','N','N','N');

.......

insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('SYS','LOBCOMPPART$',NULL,'302','302','TABLE',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DATE('15-A
PR-10', 'DD-MON-RR'),'2010-04-15:13:14:46','VALID','N','N','N');

insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('SYS','I_LOBFRAG$_FRAGOBJ$',NULL,'301','301','INDEX',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DAT
E('15-APR-10', 'DD-MON-RR'),'2010-04-15:13:14:46','VALID','N','N','N');

91 rows selected.

Elapsed: 00:00:00.06
SQL> spool off
SQL>
SQL> !
[ora10g@killdb ~]$ pwd
/home/ora10g
[ora10g@killdb ~]$ cat test_undo1_insert.sql |grep insert|wc -l
90
[ora10g@killdb ~]$

++++++++++++ 方法 3 使用bbed 定位XID
如果操作的数据刚好都在一个block,即一共block内数据被全部删除,那么无法通过第2种的边界方法去定位.
首先我这里用一个例子来展示,将一个block的数据全部delete掉,但是需要先定位到该block的数据范围:

BBED> set file 2 block 73705
FILE# 2
BLOCK# 73705
BBED> p kdbr
sb2 kdbr[0] @142 7981
sb2 kdbr[1] @144 7893
......
sb2 kdbr[80] @302 1115
sb2 kdbr[81] @304 1021

BBED> p *kdbr[0]
rowdata[7048]
-------------
ub1 rowdata[7048] @8105 0x2c

BBED> x /rccccccccccccccccccccccccccccc
rowdata[7048] @8105
-------------
flag@8105: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8106: 0x00
cols@8107: 13

col 0[5] @8108: OUTLN
col 1[10] @8114: OL$HNT_NUM
col 2[0] @8125: *NULL*
col 3[3] @8126: <
col 4[3] @8130: <
col 5[5] @8134: INDEX
col 6[7] @8140: xn....0
col 7[7] @8148: xn....0
col 8[19] @8156: 2010-04-15:13:14:47
col 9[5] @8176: VALID
col 10[1] @8182: N
col 11[1] @8184: N
col 12[1] @8186: N

BBED> x /rnnnnnnnnnnnnnnnnnnnnnnn
rowdata[7048] @8105
-------------
flag@8105: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8106: 0x00
cols@8107: 13

col 0[5] @8108: #########################################
col 1[10] @8114: #########################################
col 2[0] @8125: *NULL*
col 3[3] @8126: 459
col 4[3] @8130: 459
col 5[5] @8134: #########################################
col 6[7] @8140: #########################################
col 7[7] @8148: #########################################
col 8[19] @8156: #########################################
col 9[5] @8176: #########################################
col 10[1] @8182: #########################################
col 11[1] @8184: #########################################
col 12[1] @8186: #########################################

BBED> p *kdbr[81]
rowdata[88]
-----------
ub1 rowdata[88] @1145 0x2c

BBED> x /rnnnnnnnnnnnnnnnnnnnn
rowdata[88] @1145
-----------
flag@1145: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@1146: 0x00
cols@1147: 13

col 0[3] @1148: #########################################
col 1[25] @1152: 0x53 0x59 0x53 0x5f 0x4c 0x4f 0x42 0x30 0x30 0x30
0x30 0x30 0x30 0x30 0x35 0x34 0x35 0x43 0x30 0x30 0x30 0x30 0x33
0x24 0x24
col 2[0] @1178: *NULL*
col 3[3] @1179: 546
col 4[3] @1183: 546
col 5[3] @1187: #########################################
col 6[7] @1191: #########################################
col 7[7] @1199: #########################################
col 8[19] @1207: #########################################
col 9[5] @1227: #########################################
col 10[1] @1233: #########################################
col 11[1] @1235: #########################################


从上面可以看出,该block内的数据范围在object_id 459和546之间,将其全部delete掉:

SQL> show user
USER is "ROGER"
SQL> delete from test_undo1 where object_id >=459 and object_id <=546;

82 rows deleted.

SQL> commit;

Commit complete.

SQL>



通过bbed来获取xid,首先观察操作前后的itl信息变化,如下:

----delete操作之后

struct ktbbhitl[0], 24 bytes @44
struct ktbitxid, 8 bytes @44
ub2 kxidusn @44 0xffff
ub2 kxidslt @46 0x0000
ub4 kxidsqn @48 0x00000000
struct ktbituba, 8 bytes @52
ub4 kubadba @52 0x00000000
ub2 kubaseq @56 0x0000
ub1 kubarec @58 0x00
ub2 ktbitflg @60 0x8000 (KTBFCOM)
union _ktbitun, 2 bytes @62
b2 _ktbitfsc @62 0
ub2 _ktbitwrp @62 0x0000
ub4 ktbitbas @64 0x007f0cc2
struct ktbbhitl[1], 24 bytes @68
struct ktbitxid, 8 bytes @68
ub2 kxidusn @68 0x000e
ub2 kxidslt @70 0x002d
ub4 kxidsqn @72 0x00000395
struct ktbituba, 8 bytes @76
ub4 kubadba @76 0x0180504f
ub2 kubaseq @80 0x0995
ub1 kubarec @82 0x12
ub2 ktbitflg @84 0x8000 (KTBFCOM)
union _ktbitun, 2 bytes @86
b2 _ktbitfsc @86 0
ub2 _ktbitwrp @86 0x0000
ub4 ktbitbas @88 0x007f342a
struct ktbbhitl[2], 24 bytes @92
struct ktbitxid, 8 bytes @92
ub2 kxidusn @92 0x0014
ub2 kxidslt @94 0x0003
ub4 kxidsqn @96 0x0000039d
struct ktbituba, 8 bytes @100
ub4 kubadba @100 0x018017ba
ub2 kubaseq @104 0x0855
ub1 kubarec @106 0x0b
ub2 ktbitflg @108 0x2052 (KTBFUPB)
union _ktbitun, 2 bytes @110
b2 _ktbitfsc @110 6881
ub2 _ktbitwrp @110 0x1ae1
ub4 ktbitbas @112 0x00838226

在不考虑ITL被覆盖的情况下,显然该事务所使用的itl应该是最后一个.


从这里我们可以看出对应的事务XID为:0x0014 0003 0000039d

转换为FLASHBACK_TRANSACTION_QUERY试图的标准xid格式为:140003009d030000

获得到xid后,我们就可以直接查询获得undo_sql文本了,如下:

SQL> spool test_undo1_insert2.sql
SQL> select undo_sql from FLASHBACK_TRANSACTION_QUERY where xid=hextoraw('140003009d030000');

UNDO_SQL
------------------------------------------------------------------------------------------------------------------------------------------------------
insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('SYS','SYS_LOB0000000545C00003$$',NULL,'546','546','LOB',TO_DATE('15-APR-10', 'DD-MON-RR'),TO
_DATE('15-APR-10', 'DD-MON-RR'),'2010-04-15:13:14:49','VALID','N','Y','N');

......
insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('OUTLN','OL$NODE_OL_NAME',NULL,'460','460','INDEX',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DATE(
'15-APR-10', 'DD-MON-RR'),'2010-04-15:13:14:47','VALID','N','N','N');

insert into "ROGER"."TEST_UNDO1"("OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAM
P","STATUS","TEMPORARY","GENERATED","SECONDARY") values ('OUTLN','OL$HNT_NUM',NULL,'459','459','INDEX',TO_DATE('15-APR-10', 'DD-MON-RR'),TO_DATE('15-A
PR-10', 'DD-MON-RR'),'2010-04-15:13:14:47','VALID','N','N','N');

83 rows selected.

Elapsed: 00:00:00.03
SQL> spool off
SQL> !
[ora10g@killdb ~]$ cat test_undo1_insert2.sql |grep insert|wc -l
82
[ora10g@killdb ~]$

我们可以发现,刚好82条记录,也就是该block中被删除的所有记录,一共82条.



备注: 本文不考虑block itl被覆盖的情况,如果block itl被覆盖,那么情况更为复制,大家可以一起研究下.
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论