Oracle中怎么导出索引数据块?

December 17, 2023
测试
测试
测试
测试
13 分钟阅读

Oracle唯一索引和NULL空值之间的关系》文章写到了dump索引数据块,当我们需要看一些数据表、索引在块上的存储形式时,dump数据块是一种很直接的操作。

1. 创建测试表,含1000条数据,创建唯一索引,

SQL> create table tt1 as select owner, object_id, object_name from dba_objects where rownum < 1001;
Table created.


SQL> create unique index idx_tt1_01 on tt1(owner, object_id, object_name);
Index created.


SQL> select count(*) from tt1;
  COUNT(*)
----------
      1000

可知他现在有5个叶子节点块,索引层高为2,

SQL> select table_name,index_name,blevel,leaf_blocks,num_rows,last_analyzed,degree,status from user_indexes where table_name='TT1';
TABLE_NAME                INDEX_NAME                    BLEVEL LEAF_BLOCKS   NUM_ROWS LAST_ANALYZED      DEGREE                                   STATUS
------------------------- ------------------------- ---------- ----------- ---------- ------------------ ---------------------------------------- --------
TT1                       IDX_TT1_01                         1           5       1000 26-APR-22          1                                        VALID

2. 查询索引的object_id,

SQL> select object_id from user_objects where object_name='IDX_TT1_01';
 OBJECT_ID
----------
     73011

3. 查询索引的treedump,此处的参数,就是索引的object_id,

SQL> alter session set events 'immediate trace name treedump level 73011';
Session altered.

4. 到Oracle的trace路径下,可以直接cd,或者通过oradebug setmypid -> oradebug tracefile_name得到trace文件名,文件片段如下,可以看到有5个leaf,这和上面查询到的索引包含5个节点叶子块是一致的,

----- begin tree dump
*** 2022-04-25T19:08:55.943552+08:00 (BISALPDB1(3))
branch: 0x3002bbb 50342843 (0: nrow: 5, level: 1)
   leaf: 0x3002bbc 50342844 (-1: row:270.270 avs:837)
   leaf: 0x3002bbd 50342845 (0: row:225.225 avs:816)
   leaf: 0x3002bbe 50342846 (1: row:224.224 avs:840)
   leaf: 0x3002bbf 50342847 (2: row:234.234 avs:826)
   leaf: 0x3002bc0 50342850 (3: row:50.50 avs:6158)
----- end tree dump

5. 我们可以dump其中一个索引叶子节点的数据块,例如第五个leaf,根据值50342850,通过dbms_utility包的data_block_address_file和data_block_address_block就可以得到这个索引叶子节点对应的数据文件号、数据块号,此处是12号文件的第11200个数据块,

SQL> select dbms_utility.data_block_address_file(50342850) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(50342850)
----------------------------------------------
                                            12


SQL> select dbms_utility.data_block_address_block(50342850) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(50342850)
-----------------------------------------------
                                          11200

6. dump索引数据块,

SQL> alter system dump datafile 12 block 11200;
System altered.

从trace路径,就可以找到dump出来的文件,从以下位置开始,就是索引数据块的信息了,可以看到typ:2-INDEX表示他是个索引的数据块,

Block header dump:  0x03003b70
 Object id on Block? Y
 seg/obj: 0x11d33  csc:  0x0000000000f8b3d6  itc: 2  flg: E  typ: 2 - INDEX
     brn: 1  bdba: 0x3003b68 ver: 0x01 opc: 0
     inc: 0  exflg: 0


 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x02   0x0008.00d.000007f7  0x024000f6.02bf.17  --U-    1  fsc 0x0000.00f8b3f1
Leaf block dump
===============
header address 1981317220=0x76188064
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 3
kdxcosdc 0
kdxconro 127
kdxcofbo 290=0x122
kdxcofeo 3435=0xd6b
kdxcoavs 3145
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 50346863=0x3003b6f
kdxledsz 6
kdxlebksz 8032
row#0[7990] flag: -------, lock: 0, len=42, data:(6):  03 00 2b d6 00 60
col 0; len 3; (3):  53 59 53
col 1; len 3; (3):  c2 09 4d
col 2; len 25; (25):
 53 59 53 5f 4c 4f 42 30 30 30 30 30 30 30 38 37 35 43 30 30 30 34 38 24 24
row#1[7949] flag: -------, lock: 0, len=41, data:(6):  03 00 2b d6 00 5f
col 0; len 3; (3):  53 59 53
col 1; len 3; (3):  c2 09 4e
col 2; len 24; (24):
 53 59 53 5f 49 4c 30 30 30 30 30 30 30 38 37 35 43 30 30 30 34 38 24 24
row#2[7907] flag: -------, lock: 0, len=42, data:(6):  03 00 2b d6 00 5e
col 0; len 3; (3):  53 59 53
col 1; len 3; (3):  c2 09 4f
col 2; len 25; (25):
 53 59 53 5f 4c 4f 42 30 30 30 30 30 30 30 38 37 35 43 30 30 30 34 39 24 24


...


row#125[3449] flag: -------, lock: 0, len=32, data:(6):  03 00 2b d6 00 da
col 0; len 3; (3):  53 59 53
col 1; len 3; (3):  c2 0b 02
col 2; len 15; (15):  41 50 50 4c 59 24 5f 43 44 52 5f 49 4e 46 4f
row#126[3435] flag: -------, lock: 2, len=14, data:(6):  03 00 2b d7 00 00
col 0; len 1; (1):  61
col 1; len 2; (2):  c1 02
col 2; NULL
----- end of leaf block Logical dump -----
----- end of leaf block dump -----

以第126行为例,

第1行的data(6)是rowid,

第2-4行是第1-3列索引值,

row#125[3449] flag: -------, lock: 0, len=32, data:(6):  03 00 2b d6 00 da
col 0; len 3; (3):  53 59 53
col 1; len 3; (3):  c2 0b 02
col 2; len 15; (15):  41 50 50 4c 59 24 5f 43 44 52 5f 49 4e 46 4f

1. rowid

"data:(6): 03 00 2b d6 00 da"是16进制的rowid,先转成二进制,

00000011 00000000 00101011 11010110 00000000 11011010

按照rowid组成规则,

(1) 对应文件编号,表明该行所在文件的编号,表空间的每一个文件标号都是唯一的,文件编号所占用的位置是10位,如下所示,

00000011 00,10进制的文件号:12

(2) 块编号,表明改行所在文件的块的位置块编号需要22位,如下所示,

000000 00101011 11010110,10进制的块号:11222

(3) 行编号,表明该行在行目录中的具体位置行编号需要16位,如下所示,

00000000 11011010,10进制的行号:218

即第126行的数据是在第10个数据文件中第11222个数据块的第218行。

2. 索引实际值

col 0; len 3; (3):  53 59 53
col 1; len 3; (3):  c2 0b 02
col 2; len 15; (15):  41 50 50 4c 59 24 5f 43 44 52 5f 49 4e 46 4f

dump文件中的索引值,可以转成实际的索引列的值,此时可以借助travel大神的函数f_get_from_dump,原始下载地址,应该被墙了,常规操作不让访问了,

http://www.traveldba.com/wp-content/uploads/scripts/f_get_from_dump.sql

除了翻墙,可以从我的github下载,

https://github.com/bisal-liu/oracle/blob/master/f_get_from_dump

他支持数值类型、字符串类型、ROWID类型等的转换,以第126行为例,

(1) 第一列是VARCHAR2类型的,

col 0; len 3; (3):  53 59 53

调用函数f_get_from_dump,得到值SYS,

SQL> select f_get_from_dump('53,59,53','VARCHAR2') from dual;
F_GET_FROM_DUMP('53,59,53','VARCHAR2')
--------------------------------------------------------------------------------
SYS

(2) 第二列是NUMBER类型的,

col 1; len 3; (3):  c2 0b 02

调用函数f_get_from_dump,得到值1001,,

SQL> select f_get_from_dump('c2,0b,02','NUMBER') from dual;
F_GET_FROM_DUMP('C2,0B,02','NUMBER')
--------------------------------------------------------------------------------
1001

(3) 第三列是VARCHAR2类型的,

col 2; len 15; (15):  41 50 50 4c 59 24 5f 43 44 52 5f 49 4e 46 4f

调用函数f_get_from_dump,得到值APPLY$_CDR_INFO,

SQL> select f_get_from_dump('41,50,50,4c,59,24,5f,43,44,52,5f,49,4e,46,4f','VARCHAR2') from dual;
F_GET_FROM_DUMP('41,50,50,4C,59,24,5F,43,44,52,5F,49,4E,46,4F','VARCHAR2')
--------------------------------------------------------------------------------
APPLY$_CDR_INFO

从这些数据块的文件中,我们就可以了解表的数据、索引的数据是怎么物理存储的,对于理解一些原理层的知识,非常有用,当然要做到融会贯通,从现象到本质,还得加以时日的训练,还在学习中。

继续阅读

更多来自我们博客的帖子

如何安装 BuddyPress
由 测试 December 17, 2023
经过差不多一年的开发,BuddyPress 这个基于 WordPress Mu 的 SNS 插件正式版终于发布了。BuddyPress...
阅读更多
Filter如何工作
由 测试 December 17, 2023
在 web.xml...
阅读更多
如何理解CGAffineTransform
由 测试 December 17, 2023
CGAffineTransform A structure for holding an affine transformation matrix. ...
阅读更多