drop table test;
create table test(goodid char(8),OBJECT_NAME varchar(100));
insert into test select a.object_id,a.object_name from warecountd a
SQL> desc test;
Name Type Nullable Default Comments
----------- ------------- -------- ------- --------
GOODID CHAR(8) Y
OBJECT_NAME VARCHAR2(100) Y
2. B树索引的内部结构
我们可以使用如下方式将B树索引转储成树状结构的形式而呈现出来:
SQL> select min(goodid),min(to_number(goodid)),max(goodid),max(to_number(goodid)) from test;
MIN(GOODID) MIN(TO_NUMBER(GOODID)) MAX(GOODID) MAX(TO_NUMBER(GOODID))
----------- ---------------------- ----------- ----------------------
50000 50000 88992 88992
创建索引:
create index IDX_WARECOUNTD_GOODID on test(goodid);
SQL> create index IDX_WARECOUNTD_GOODID on test(goodid);
Index created
收集统计信息:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'TEST',
tabname => 'TEST',
estimate_percent => 100,
method_opt => 'for all columns size repeat',
no_invalidate => FALSE,
degree => 8,
cascade => TRUE);
END;
我们可以使用如下方式将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';
SQL> select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/diag/rdbms/serv/serv/trace/serv_ora_30132.trc
alter session set events 'immediate trace name treedump level 89037';
/oracle/app/diag/rdbms/serv/serv/trace/serv_ora_30132.trc
----- begin tree dump
branch: 0x103151b 16979227 (0: nrow: 7, level: 2)
branch: 0x1031735 16979765 (-1: nrow: 419, level: 1)
leaf: 0x103151c 16979228 (-1: nrow: 359 rrow: 359)
leaf: 0x103151d 16979229 (0: nrow: 359 rrow: 359)
leaf: 0x103151e 16979230 (1: nrow: 359 rrow: 359)
leaf: 0x103151f 16979231 (2: nrow: 359 rrow: 359)
leaf: 0x1031520 16979232 (3: nrow: 359 rrow: 359)
leaf: 0x1031521 16979233 (4: nrow: 359 rrow: 359)
leaf: 0x1031522 16979234 (5: nrow: 359 rrow: 359)
leaf: 0x1031523 16979235 (6: nrow: 359 rrow: 359)
leaf: 0x1031524 16979236 (7: nrow: 359 rrow: 359)
leaf: 0x1031525 16979237 (8: nrow: 359 rrow: 359)
branch: 0x10318e0 16980192 (0: nrow: 420, level: 1)
leaf: 0x1031734 16979764 (-1: nrow: 359 rrow: 359)
leaf: 0x1031736 16979766 (0: nrow: 359 rrow: 359)
leaf: 0x1031737 16979767 (1: nrow: 359 rrow: 359)
leaf: 0x1031738 16979768 (2: nrow: 359 rrow: 359)
leaf: 0x1031739 16979769 (3: nrow: 359 rrow: 359)
leaf: 0x103173a 16979770 (4: nrow: 359 rrow: 359)
leaf: 0x103173b 16979771 (5: nrow: 359 rrow: 359)
leaf: 0x103173c 16979772 (6: nrow: 359 rrow: 359)
0x1031734 16进制 转换为16979764
0x10318e0 16进制 转换为 16980192
其中,每一行的第一列表示节点类型:branch表示分支节点(包括根节点),而leaf则表示叶子节点;
第二列表示十六进制表示的节点的地址;第三列表示十进制表示的节点的地址;
第四列表示相对于前一个节点的位置,根节点从0开始计算,其他分支节点和叶子节点从-1开始计算;
第五列的nrow表示当前节点中所含有的索引条目的数量。比如我们可以看到根节点中含有的nrow为9,
表示根节点中含有9个索引条目,分别指向9个分支节点;第六列中的level表示分支节点的层级,
对于叶子节点来说level都是0。第六列中的rrow表示有效的索引条目(因为索引条目如果被删除,不会立即被清除出索引块中。
所以nrow减rrow的数量就表示已经被删除的索引条目数量)的数量,比如对于第一个leaf来说,其rrow为359,
也就是说该叶子节点中存放了359个可用索引条目,分别指向表warecountd的359条记录。
上面这种方式以树状形式转储整个索引。同时,我们可以转储一个索引节点来看看其中存放了些什么。转储的方式为:
我们从上面转储结果中的第二行知道,索引的根节点的地址为16979227,因此我们先将其转换为文件号以及数据块号
select dbms_utility.data_block_address_file(16979227), dbms_utility.data_block_address_block(16979227) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRES DBMS_UTILITY.DATA_BLOCK_ADDRES
SQL> set linesize 200
SQL> set pagesize 200
SQL> select dbms_utility.data_block_address_file(16979227),
dbms_utility.data_block_address_block(16979227)
from dual; 2 3
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16979227) DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16979227)
---------------------------------------------- -----------------------------------------------
4 202011
select value from v$diag_info where name='Default Trace File';
alter system dump datafile 4 block 202011;
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.0023604a
Branch block dump
=================
header address 140001912396364=0x7f54bc419a4c
kdxcolev 2
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 6
kdxcofbo 40=0x28
kdxcofeo 7952=0x1f10
kdxcoavs 7912
kdxbrlmc 16979765=0x1031735
kdxbrsno 0
kdxbrbksz 8056
kdxbr2urrc 0
row#0[8039] dba: 16980192=0x10318e0
col 0; len 8; (8): 35 34 37 30 30 20 20 20 --54700
col 1; len 3; (3): 01 03 8a
row#1[8022] dba: 16980621=0x1031a8d
col 0; len 8; (8): 35 39 34 31 32 20 20 20 --59412
col 1; len 3; (3): 01 03 88
row#2[8005] dba: 16981176=0x1031cb8
col 0; len 8; (8): 36 34 31 32 34 20 20 20
col 1; len 3; (3): 01 03 85
row#3[7987] dba: 16981603=0x1031e63
col 0; len 8; (8): 36 38 38 33 39 20 20 20
col 1; len 4; (4): 01 03 82 c9
row#4[7969] dba: 16982031=0x103200f
col 0; len 8; (8): 38 30 37 34 35 20 20 20
col 1; len 4; (4): 01 03 7f 88
row#5[7952] dba: 16982245=0x10320e5
col 0; len 8; (8): 38 35 34 35 36 20 20 20
col 1; len 3; (3): 01 03 8d
----- end of branch block dump -----
End dump data blocks tsn: 4 file#: 4 minblk 202011 maxblk 202011
其中的kdxcolev表示索引层级号,这里由于我们转储的是根节点,所以其层级号为2
kdxconro表示当前索引节点中索引条目的数量
每个索引条目都指向一个分支节点。其中col 1表示所链接的分支节点的地址,该值经过一定的转换以后实际就是row#所在行的dba的值。
row#0[8039] dba: 16980192=0x10318e0
10进制 16进制
col 0; len 8; (8): 35 34 37 30 30 20 20 20
则将其中每对值都使用函数to_number(NN,’XX’)的方式从十六进制转换为十进制
转换 53 52 55 48 48 32 32 32
于是我们得到转换后的值:53 52 55 48 48 32 32 32,因为我们已经知道索引键值是char类型的,
5 4 7 0 0
所以对每个值都运用chr函数就可以得到被索引键值为:54700。
通过存储过程转换
col 0; len 8; (8): 35 34 37 30 30 20 20 20
col 1; len 3; (3): 01 03 8a
DECLARE
n VARCHAR2(2000);
BEGIN
DBMS_STATS.convert_raw_value('35', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('34', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('37', n);
DBMS_OUTPUT.put_line(n);
DBMS_STATS.convert_raw_value('30', 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;
转换出来为54700
select dump('54700') from dual;
Typ=96 Len=5: 53,52,55,48,48
54700 col 0; len 8; (8): 35 34 37 30 30 20 20 20 的最小键值
转换后的值为
54700,59412,64124,68836