(转)深入研究B树索引(二)

2.     B 树索引的内部结构

我们可以使用如下方式将 B 树索引转储成树状结构的形式而呈现出来:

Sql代码   收藏代码
  1. alter  session  set  events  'immediate trace name treedump level INDEX_OBJECT_ID'   

 

       比如,对于上面的例子来说,我们把创建在 goodid 上的名为 idx_warecountd_goodid 的索引转储出来。

Sql代码   收藏代码
  1. SQL>  select  object_id  from  user_objects  where  object_name= 'IDX_WARECOUNTD_GOODID' ;  
  2.   
  3.  OBJECT_ID  
  4.   
  5. ----------   
  6.   
  7.      7378  
  8.   
  9. SQL> alter  session  set  events  'immediate trace name treedump level 7378' ;  

 

       打开转储出来的文件以后,我们可以看到类似下面的内容:

Sql代码   收藏代码
  1. ----- begin tree dump   
  2.   
  3. branch: 0x180eb0a 25225994 (0: nrow: 9, level : 2)  
  4.   
  5.   branch: 0x180eca1 25226401 (-1: nrow: 405, level : 1)  
  6.   
  7.      leaf: 0x180eb0b 25225995 (-1: nrow: 359 rrow: 359)  
  8.   
  9.      leaf: 0x180eb0c 25225996 (0: nrow: 359 rrow: 359)  
  10.   
  11.      leaf: 0x180eb0d 25225997 (1: nrow: 359 rrow: 359)  
  12.   
  13.      leaf: 0x180eb0e 25225998 (2: nrow: 359 rrow: 359)  
  14.   
  15. …………………  
  16.   
  17.   branch: 0x180ee38 25226808 (0: nrow: 406, level : 1)  
  18.   
  19.      leaf: 0x180eca0 25226400 (-1: nrow: 359 rrow: 359)  
  20.   
  21.      leaf: 0x180eca2 25226402 (0: nrow: 359 rrow: 359)  
  22.   
  23.      leaf: 0x180eca3 25226403 (1: nrow: 359 rrow: 359)  
  24.   
  25.      leaf: 0x180eca4 25226404 (2: nrow: 359 rrow: 359)  
  26.   
  27. …………………  

 

       其中,每一行的第一列表示节点类型: branch 表示分支节点(包括根节点),而 leaf 则表示叶子节点;第二列表示十六进制表示的节点的地址;第三列表示十进制表示的节点的地址;第四列表示相对于前一个节点的位置,根节点从 0 开始计算,其他分支节点和叶子节点从 -1 开始计算;第五列的 nrow 表示当前节点中所含有的索引条目的数量。比如我们可以看到根节点中含有的 nrow9 ,表示根节点中含有 9 个索引条目,分别指向 9 个分支节点;第六列中的 level 表示分支节点的层级,对于叶子节点来说 level 都是 0 。第六列中的 rrow 表示有效的索引条目(因为索引条目如果被删除,不会立即被清除出索引块中。所以 nrowrrow 的数量就表示已经被删除的索引条目数量)的数量,比如对于第一个 leaf 来说,其 rrow359 ,也就是说该叶子节点中存放了 359 个可用索引条目,分别指向表 warecountd359 条记录。

       上面这种方式以树状形式转储整个索引。同时,我们可以转储一个索引节点来看看其中存放了些什么。转储的方式为:

Sql代码   收藏代码
  1. alter  system dump datafile file# block block#;   

 

       我们从上面转储结果中的第二行知道,索引的根节点的地址为 25225994 ,因此我们先将其转换为文件号以及数据块号。

Sql代码   收藏代码
  1. SQL>  select  dbms_utility.data_block_address_file(25225994),  
  2.   
  3.  2 dbms_utility.data_block_address_block(25225994) from  dual;  
  4.   
  5. DBMS_UTILITY.DATA_BLOCK_ADDRES DBMS_UTILITY.DATA_BLOCK_ADDRES  
  6.   
  7. ------------------------------ ------------------------------   
  8.   
  9.                             6                         60170  

 

       于是,我们转储根节点的内容。

Sql代码   收藏代码
  1. SQL>  alter  system dump datafile 6 block 60170;   

 

       打开转储出来的跟踪文件,我们可以看到如下的索引头部的内容:

Sql代码   收藏代码
  1. header address 85594180=0x51a1044  
  2.   
  3. kdxcolev 2  
  4.   
  5. KDXCOLEV Flags = - - -  
  6.   
  7. kdxcolok 0  
  8.   
  9. kdxcoopc 0x80: pcode=0: iot flags=--- is converted=Y   
  10.   
  11. kdxconco 2  
  12.   
  13. kdxcosdc 0  
  14.   
  15. kdxconro 8  
  16.   
  17. kdxcofbo 44=0x2c  
  18.   
  19. kdxcofeo 7918=0x1eee  
  20.   
  21. kdxcoavs 7874  
  22.   
  23. kdxbrlmc 25226401=0x180eca1  
  24.   
  25. kdxbrsno 0  
  26.   
  27. kdxbrbksz 8060   

 

       其中的 kdxcolev 表示索引层级号,这里由于我们转储的是根节点,所以其层级号为 2 。对叶子节点来说该值为 0kdxcolok 表示该索引上是否正在发生修改块结构的事务; kdxcoopc 表示内部操作代码; kdxconco 表示索引条目中列的数量; kdxcosdc 表示索引结构发生变化的数量,当你修改表里的某个索引键值时,该值增加; kdxconro 表示当前索引节点中索引条目的数量,但是注意,不包括 kdxbrlmc 指针; kdxcofbo 表示当前索引节点中可用空间的起始点相对当前块的位移量; kdxcofeo 表示当前索引节点中可用空间的最尾端的相对当前块的位移量; kdxcoavs 表示当前索引块中的可用空间总量,也就是用 kdxcofeo 减去 kdxcofbo 得到的。 kdxbrlmc 表示分支节点的地址,该分支节点存放了索引键值小于 row#0 (在转储文档后半部分显示)所含有的最小值的所有节点信息; kdxbrsno 表示最后一个被修改的索引条目号,这里看到是 0 ,表示该索引是新建的索引; kdxbrbksz 表示可用数据块的空间大小。实际从这里已经可以看到,即便是 PCTFREE 设置为 0 ,也不能用足 8192 字节。

       再往下可以看到如下的内容。这部分内容就是在根节点中所记录的索引条目,总共是 8 个条目。再加上

Sql代码   收藏代码
  1. row#0[8043] dba: 25226808=0x180ee38  
  2.   
  3. col 0; len 8; (8): 31 30 30 30 30 33 39 32  
  4.   
  5. col 1; len 3; (3): 01 40 1a  
  6.   
  7. ……  
  8.   
  9. row#7[7918] dba: 25229599=0x180f91f  
  10.   
  11. col 0; len 8; (8): 31 30 30 31 31 32 30 33  
  12.   
  13. col 1; len 4; (4): 01 40 8f a5   

 

kdxbrlmc 所指向的第一个分支节点,我们知道该根节点中总共存放了 9 个分支节点的索引条目,而这正是我们在前面所指出的为了管理 3611 个叶子节点,我们需要 9 个分支节点。

每个索引条目都指向一个分支节点。其中 col 1 表示所链接的分支节点的地址,该值经过一定的转换以后实际就是 row# 所在行的 dba 的值。如果根节点下没有其他的分支节点,则 col 1TERMcol 0 表示该分支节点所链接的最小键值。其转换方式非常复杂,比如对于 row #0 来说, col 031 30 30 30 30 30 30 33 ,则将其中每对值都使用函数 to_number(NN,’XX’) 的方式从十六进制转换为十进制,于是我们得到转换后的值: 49,48,48,48,48,48,48,51 ,因为我们已经知道索引键值是 char 类型的,所以对每个值都运用 chr 函数就可以得到被索引键值为: 10000003 。实际上,对 10000003 运用 dump 函数得到的结果就是: 49,48,48,48,48,48,48,51 。所以我们也就知道, 10000003 就是 dba25226808 的索引块所链接的最小键值。

Sql代码   收藏代码
  1. SQL>  select  dump( '10000003'from  dual;  
  2.   
  3. DUMP('10000003' )  
  4.   
  5. -------------------------------------   
  6.   
  7. Typ=96 Len=8: 49,48,48,48,48,48,48,50  
  8.    

 

       接下来,我们从根节点中随便找一个分支节点,假设就是 row#0 所描述的 25226808 。对其运用前面所介绍过的 dbms_utility 里的存储过程获得其文件号和数据块号,并对该数据块进行转储,其内容如下所示。可以

Sql代码   收藏代码
  1. row#0[8043] dba: 25226402=0x180eca2  
  2.   
  3. col 0; len 8; (8): 31 30 30 30 30 33 39 33  
  4.   
  5. col 1; len 3; (3): 01 40 2e  
  6.   
  7. ………  
  8.   
  9. row#404[853] dba: 25226806=0x180ee36  
  10.   
  11. col 0; len 8; (8): 31 30 30 30 31 36 34 30  
  12.   
  13. col 1; len 3; (3): 01 40 09  
  14.   
  15. ----- end of branch block dump -----   

 

发现内容与根节点完全类似,只不过该索引块中所包含的索引条目(指向叶子节点)的数量更多了,为 405 个。这也与我们前面所说的 一个分支索引块可以存放大约 4056488/16 )个索引条目完全一致。

       然后,我们从中随便挑一个叶子节点,对其进行转储。假设就选 row#0 行所指向的叶子节点,根据 dba 的值: 25226402 可以知道,文件号为 6 ,数据块号为 60578 。将其转储以后,其内容如下所示,我只显示与分支节点不同的部分。

Sql代码   收藏代码
  1. ………  
  2.   
  3. kdxlespl 0  
  4.   
  5. kdxlende 0  
  6.   
  7. kdxlenxt 25226403=0x180eca3  
  8.   
  9. kdxleprv 25226400=0x180eca0  
  10.   
  11. kdxledsz 0  
  12.   
  13. kdxlebksz 8036   

 

       其中的 kdxlespl 表示当叶子节点被拆分时未提交的事务数量; kdxlende 表示被删除的索引条目的数量; kdxlenxt 表示当前叶子节点的下一个叶子节点的地址; kdxlprv 表示当前叶子节点的上一个叶子节点的地址; kdxledsz 表示可用空间,目前是 0

       转储文件中接下来的部分就是索引条目部分,每个条目包含一个 ROWID ,指向一个表里的数据行。如下所示。其中 flag 表示标记,比如删除标记等;而 lock 表示锁定信息。 col 0 表示索引键值,其算法与我们在前面介绍分支节点时所说的算法一致。 col 1 表示 ROWID 。我们同样可以看到,该叶子节点中包含了 359 个索引条目,与我们前面所估计的一个叶子节点中大约可以放 360 个索引条目也是基本一致的。

Sql代码   收藏代码
  1. row#0[8018] flag:  -----, lock: 0   
  2.   
  3. col 0; len 8; (8): 31 30 30 30 30 33 39 33  
  4.   
  5. col 1; len 6; (6): 01 40 2e 93 00 16  
  6.   
  7. row#1[8000] flag: -----, lock: 0   
  8.   
  9. col 0; len 8; (8): 31 30 30 30 30 33 39 33  
  10.   
  11. col 1; len 6; (6): 01 40 2e e7 00 0e  
  12.   
  13. …………  
  14.   
  15. row#358[1574] flag: -----, lock: 0   
  16.   
  17. col 0; len 8; (8): 31 30 30 30 30 33 39 37  
  18.   
  19. col 1; len 6; (6): 01 40 18 ba 00 1f  
  20.   
  21. ----- end of leaf block dump -----  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值