2. B树索引的内部结构
我们可以使用如下方式将B树索引转储成树状结构的形式而呈现出来:
我们可以使用如下方式将B树索引转储成树状结构的形式而呈现出来:
alter session set events 'immediate trace name treedump level INDEX_OBJECT_ID';
比如,对于上面的例子来说,我们把创建在goodid上的名为idx_warecountd_goodid的索引转储出来。
SQL> select object_id from user_objects where object_name='IDX_WARECOUNTD_GOODID';
OBJECT_ID
----------
89037
SQL> alter session set events 'immediate trace name treedump level 89037';
select value from v$diag_info where name='Default Trace File';
----- begin tree dump
branch: 0x1031b23 16980771 (0: nrow: 106, level: 2)
branch: 0x10556b0 17127088 (-1: nrow: 414, level: 1)
leaf: 0x1031b24 16980772 (-1: nrow: 363 rrow: 363)
leaf: 0x1031b25 16980773 (0: nrow: 359 rrow: 359)
leaf: 0x1031b26 16980774 (1: nrow: 359 rrow: 359)
leaf: 0x1031b27 16980775 (2: nrow: 359 rrow: 359)
leaf: 0x1031b28 16980776 (3: nrow: 359 rrow: 359)
leaf: 0x1031b29 16980777 (4: nrow: 359 rrow: 359)
leaf: 0x1031b2a 16980778 (5: nrow: 359 rrow: 359)
leaf: 0x1031b2b 16980779 (6: nrow: 359 rrow: 359)
leaf: 0x1031b2c 16980780 (7: nrow: 359 rrow: 359)
leaf: 0x1031b2d 16980781 (8: nrow: 359 rrow: 359)
leaf: 0x1031b2e 16980782 (9: nrow: 359 rrow: 359)
其中,每一行的第一列表示节点类型:branch表示分支节点(包括根节点),
而leaf则表示叶子节点;
第二列表示十六进制表示的节点的地址;
0x1031b23 十六进制 转换为10进制 16980771
第四列表示相对于前一个节点的位置,根节点从0开始计算
其他分支节点和叶子节点从-1开始计算
第五列的nrow表示当前节点中所含有的索引条目的数量。
上面这种方式以树状形式转储整个索引。同时,我们可以转储一个索引节点来看看其中存放了些什么。转储的方式为:
alter system dump datafile file# block block#;
我们从上面转储结果中的第二行知道,索引的根节点的地址为16980771,因此我们先将其转换为文件号以及数据块号。
select dbms_utility.data_block_address_file(16980771), dbms_utility.data_block_address_block(16980771) from dual;
SQL> select dbms_utility.data_block_address_file(16980771), dbms_utility.data_block_address_block(16980771) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16980771) DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16980771)
---------------------------------------------- -----------------------------------------------
4 203555
于是,我们转储根节点的内容。
SQL> alter system dump datafile 4 block 203555;
Branch block dump
=================
header address 140711254186060=0x7ff9e452584c
kdxcolev 2
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 105
kdxcofbo 238=0xee
kdxcofeo 6245=0x1865
kdxcoavs 6007
kdxbrlmc 17127088=0x10556b0
kdxbrsno 0
kdxbrbksz 8056
kdxbr2urrc 1
row#0[8039] dba: 17127509=0x1055855
col 0; len 8; (8): 35 30 32 39 30 20 20 20
col 1; len 3; (3): 01 03 3c
row#1[8022] dba: 17127931=0x10559fb
col 0; len 8; (8): 35 30 35 38 30 20 20 20
col 1; len 3; (3): 01 03 f0
row#2[8004] dba: 17128354=0x1055ba2
col 0; len 8; (8): 35 30 38 37 31 20 20 20
col 1; len 4; (4): 01 03 eb eb
row#3[7987] dba: 17128775=0x1055d47
col 0; len 8; (8): 35 31 31 36 31 20 20 20
col 1; len 3; (3): 01 04 a5
row#4[7970] dba: 17129196=0x1055eec
col 0; len 8; (8): 35 31 34 35 32 20 20 20
col 1; len 3; (3): 01 03 07
row#5[7952] dba: 17129620=0x1056094
col 0; len 8; (8): 35 31 37 34 32 20 20 20
col 1; len 4; (4): 01 03 89 46
row#6[7934] dba: 17130042=0x105623a
col 0; len 8; (8): 35 32 30 33 33 20 20 20
col 1; len 4; (4): 01 03 85 0e
row#7[7917] dba: 17130464=0x10563e0
col 0; len 8; (8): 35 32 33 32 34 20 20 20
col 1; len 3; (3): 01 03 80
row#8[7900] dba: 17130888=0x1056588
col 0; len 8; (8): 35 32 36 31 35 20 20 20
col 1; len 3; (3): 01 03 66
row#9[7883] dba: 17131310=0x105672e
row#103[6262] dba: 17170570=0x106008a
col 0; len 8; (8): 38 38 32 30 31 20 20 20
col 1; len 4; (4): 01 04 a1 b7
row#104[6245] dba: 17170718=0x106011e
col 0; len 8; (8): 38 38 35 30 34 20 20 20
col 1; len 3; (3): 01 03 04
----- end of branch block dump -----
kdxcolev 2:
其中的kdxcolev表示索引层级号,这里由于我们转储的是根节点,所以其层级号为2。
对叶子节点来说该值为0;
kdxcolok 0:
kdxcolok表示该索引上是否正在发生修改块结构的事务
kdxcosdc 0:
kdxcosdc表示索引结构发生变化的数量,当你修改表里的某个索引键值时,该值增加
kdxconro 105:
kdxconro表示当前索引节点中索引条目的数量,但是注意,不包括kdxbrlmc指针
再往下可以看到如下的内容。这部分内容就是在根节点中所记录的索引条目,总共是105个条目。再加上
kdxbrlmc所指向的第一个分支节点
每个索引条目都指向一个分支节点。其中col 1表示所链接的分支节点的地址,该值经过一定的转换以后实际就是row#所在行的dba的值。
row#0[8039] dba: 17127509=0x1055855
col 0; len 8; (8): 35 30 32 39 30 20 20 20
col 1; len 3; (3): 01 03 3c
0x1055855 16进制,转换为10进制 17127509
col 0; len 8; (8): 35 30 32 39 30 20 20 20
从十六进制转换为十进制
35 30 32 39 30 20 20 20
53 48 50 57 48 32 32 32
to_number(NN,’XX’)的方式从十六进制转换为十进制
因为我们已经知道索引键值是char类型的,所以对每个值都运用chr函数就可以得到被索引键值为
53 48 50 57 48 32 32 32
5 0 2 9 0
SQL> select dump('50290') from dual
2 ;
DUMP('50290')
----------------------------
Typ=96 Len=5: 53,48,50,57,48
利用存储过程转换:
DECLARE
n VARCHAR2(2000);
BEGIN
DBMS_STATS.convert_raw_value('35', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('30', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('32', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('39', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('30', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('20', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('20', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('20', n);
DBMS_OUTPUT.put_line(n);
END;
50290