B*tree dump

Oracle的索引是以平衡树的方式组织存储的:保存的是索引列的值,以及该行的rowid的一部分(文件号,块号,行号)
下面我们通过例子来了解一下:


1,create table test(id int,name varchar2(20))
insert into test values(1,'A');
insert into test values(2,'B');

begin
for i in 3..2000 loop
insert into test values(i,'t'||i);
end loop;
end;

2,create  index idx_test on test(id)

3,得到这个index的object_id:

SQL> select object_id  from dba_objects where object_name='IDX_TEST';

 OBJECT_ID
----------
     74560

4,将索引dump到trace文件中

alter session set events 'immediate trace name treedump level 74560';

看到结果:有两层,5个叶子节点

----- begin tree dump
branch: 0x1000c93 16780435 (0: nrow: 5, level: 1)
   leaf: 0x1000c94 16780436 (-1: nrow: 485 rrow: 485)
   leaf: 0x1000c95 16780437 (0: nrow: 479 rrow: 479)
   leaf: 0x1000c96 16780438 (1: nrow: 479 rrow: 479)
   leaf: 0x1000c97 16780439 (2: nrow: 479 rrow: 479)
   leaf: 0x1000c98 16780440 (3: nrow: 78 rrow: 78)
----- end tree dump


0x1000c93 :转为为10进制就是16780435

branch 表示的是 branch block ,它后面跟了一个十六进制表示的DBA(data block address),以及用10进制表示的DBA 
DBA 之后表示在同一层次的相对位置(root 从0开始,branch 以及leaf从 -1开始) 
nrow  表示块中包含了多少条目(包括delete的条目) 
rrow  表示块中包含的实际条目(不包括delete的条目) 
level 表示从该block到leaf的深度(leaf没有 level)


这个 branch block 的 level 为1,也就是说 从这个branch block 到 leaf block 的深度为1,根据前面的查询,这个索引的Blevel为1

验证索引的高度:

SQL> select index_name, PREFIX_LENGTH, BLEVEL, LEAF_BLOCKS from user_indexes where index_name='IDX_TEST';

INDEX_NAME         PREFIX_LENGTH  BLEVEL LEAF_BLOCKS
------------------------------ ------------- ---------- -----------
IDX_TEST           1    5

可以看到高度为1,leaf block为5

BLEVEL* NUMBER   B*-Tree level: depth of the index from its root block to its leaf blocks. A depth of 0 indicates that the root block and leaf block are the same.

LEAF_BLOCKS* NUMBER   Number of leaf blocks in the index


现在我来验证一下 branch: 0x1000c93 16780435 (0: nrow: 5, level: 1) 是不是 root block , 我查询这个 branch 的 DBA


SQL> select dbms_utility.data_block_address_file('16780435') FILE_ID,
       dbms_utility.data_block_address_block('16780435') BLOCK_ID
  from dual;  2    3 

   FILE_ID   BLOCK_ID
---------- ----------
  4  3219


Btree 索引的 root block总是segment header+1,所以我查询该索引的段头 
 
SQL>  select header_file,header_block from dba_segments where segment_name='IDX_TEST';

HEADER_FILE HEADER_BLOCK
----------- ------------
   4     3218

证明branch: 0x1000c93 16780435 (0: nrow: 5, level: 1) 就是root块,其实 treedump第一个 branch block 就是 root block


######################################################################################
到此时为止,已经从dump信息得出了索引的高度和第一个branch block就是root block的结论                                                                                 
######################################################################################
----- begin tree dump
branch: 0x1000c93 16780435 (0: nrow: 5, level: 1)
   leaf: 0x1000c94 16780436 (-1: nrow: 485 rrow: 485)
   leaf: 0x1000c95 16780437 (0: nrow: 479 rrow: 479)
   leaf: 0x1000c96 16780438 (1: nrow: 479 rrow: 479)
   leaf: 0x1000c97 16780439 (2: nrow: 479 rrow: 479)
   leaf: 0x1000c98 16780440 (3: nrow: 78 rrow: 78)
----- end tree dump


通过下面的转换可以看到上面这两个数据是可以相互转换的。

select to_number('1000c94','xxxxxxxxxxx') from dualSQL> ;

TO_NUMBER('1000C94','XXXXXXXXXXX')
----------------------------------
     16780436

SQL> select to_char('16780436','xxxxxxxxxxx') from dual;

TO_CHAR('167
------------
     1000c94

 

Oracle 中提供了dbms_utility来求的这个地址对应的文件号和块号(传入的参数是十进制的那个值).

查看这个leaf block对应的文件号和块号

select dbms_utility.data_block_address_file(16780436)fno,
dbms_utility.data_block_address_block(16780436) bkno from dual

SQL> select dbms_utility.data_block_address_file(16780436)fno,
dbms_utility.data_block_address_block(16780436) bkno from dual  2 
  3  ;

       FNO  BKNO
---------- ----------
  4  3220


得到的是第4号文件的第3220块


SQL> select file_id,block_id,blocks from dba_extents where segment_name='IDX_TEST';


   FILE_ID   BLOCK_ID   BLOCKS
---------- ---------- ----------
  4  3216        8
  4  3224        8


##################################################################################
这里得出了leaf 块存放的数据文件号和对应的块                                     
##################################################################################

5,将索引数据dump出来,dump 4号文件的3220块,alter system dump datafile 4 block 3220

row#0[8020] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 02
col 1; len 6; (6):  01 00 0c 8f 00 00
row#1[8008] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  01 00 0c 8f 00 01
row#2[7996] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 04
col 1; len 6; (6):  01 00 0c 8f 00 02
row#3[7984] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 05
col 1; len 6; (6):  01 00 0c 8f 00 03


以前三行为例,

row#0行号.

col 0第一列(本例中第一列为是id), len 2表示长度是2, (2)表示占了两个字节,c1 02是id的值(这里值是1的16进制表示)的存储表示.


col 1是rowid,01 00 0c 8f 00 00是rowid的一部分值,也是16进制的.,先要转换成2进制的,再通过各个位数代表的意义计算文件号,块号和和行号。

01 00 0c 8f 00 00 先转换为2进制:(注意前面先补足0)
10000000000001100100011110000000000000000

00000001 00000000 00001100 10001111 00000000 00000000


然后串起来之后前10位 00000001 00 表示文件号,=4

 

然后是接下来的22位 000000 00000000 00001100表示块号=3215

最后面的的16位表示行号=0

 

SQL> select rowid,
       id,
       dbms_rowid.rowid_relative_fno('AAASM/AAEAAAAyPAAA') fno,
       dbms_rowid.rowid_block_number('AAASM/AAEAAAAyPAAA') bkno,
       dbms_rowid.rowid_row_number('AAASM/AAEAAAAyPAAA') rno
  from test
 where id = 1;  2    3    4    5    6    7 

ROWID      ID      FNO       BKNO    RNO
------------------ ---------- ---------- ---------- ----------
AAASM/AAEAAAAyPAAA     1        4       3215      0

 

上面的sql得到是4号文件3125块0行.证明索引里保存的为rowid的一部分信息。


总结:dump信息包括了索引的高度,leaf block指向数据块的地址(包括数据文件好和块号),记录了一部分的rowid信息

 

 

posted @ 2013-11-20 15:52  czcb  阅读(236)  评论(0编辑  收藏  举报