B树系列文章

http://blog.csdn.net/whyangwanfu/article/details/1736278

B树是最重要的存取路径结构。B树总是平衡的,并且对任意修改操作来说,也容易维持B树的平衡。

1.B树的基本思想

   B树的每个节点都是一个页面。B树有两种类型的节点:叶子节点和索引节点。叶子节点包含要查找的数据,对聚集索引而言数据是记录,对非聚集索引,这里的数据是指索引列、主关键字(或ROWID)。索引节点不包含数据,只包含下一层节点的路由信息。

   B树索引节点的抽象数据结构如下:

ulint      F;              // 在一个索引节点中最大入口项的数量

struct

... {

  
char     *K;           //B树的key值

  PAGEID   P;            
//指向其它页面的指针

}
index_node_structure[];     // 有key-指针所组成的数组

 

   这里F定义了每个页最多存放的索引项(也可称为入口项)的数量,在实际的数据库实现当中,不会定义该数值。比如,假设在varchar列上建立索引,那么索引项的大小就是变长的,因此索引节点中存放的索引项的数量也是变化的。为了便于叙述的方便,这里设定了该值F。

Ki标识数组的第i个成员。每个索引节点包含一个有序的索引键值K1≤K2≤…≤KF,它们对这个节点的查找空间加以划分。每个索引键值Ki的后面都跟着一个指向其它后继节点的指针Pi,该后续节点包含位于Ki和Ki+1之间的那些索引键值Kj(Ki≤Kji+1)有关的所有信息。同样,小于索引键值K1的信息保存在P0指向的子树中。

   上面申明的结构中包含一个附加的索引键值K0,它正好位于索引序列的开始处。如果规定P0指向的子树中包含所有小于K1的索引值,那么实际上不需要该索引值(也就是,index_node_structure[0]中的K成员的值无意义)。尽管如此,大多数的B树实现中还是包含该字段的,这使得节点的内部结构变得更加简单:因为可以统一使用规则的<索引键值,指针>对数组结构,而不必使用另外一个指针。

   所有的内部节点都包含这种路由信息,即索引键和指向下层节点的指针,在下层节点中含有更详细的信息。

   叶子节点基本上也是相同的结构,但不包含其它节点的指针。需要注意的是,在索引节点中第一个记录K0是无意义的,但对叶子节点来说,它却是重要的,是该叶子节点的第一个元组。

2.B树上的查找操作

 

 

        参照图1,描述一个查找属性值=s的检索元组的操作。查找总是根节点开始,根节点是一个索引节点。令m(m≤F)为当前节点中具有最大索引键值的入口项索引,则存在以下两种情况:

  1)若s≥Km,则转到Pm指向的子树;否则,

  2)转到指针Pj指向的子树,这里Ki≤sj+1。

     如果指针指向的节点是一个索引节点,那么重复以上过程。最终指针将会指向一个叶子节点。索引键值=s的元组要么在该叶子节点中,要么根本不存在。在叶子节点内部进行的查找是利用二分查找。

      对于s≤属性值≤t形式的范围查询,因为B树在叶子页之间存在全序。所以该范围查找的执行过程为:

     1)沿B树向下查找值范围的下限,即执行属性值=s的精确匹配查询。这样定位的元组是满足该查找条件的第一个元组。

     2)沿着叶子节点中该记录向后扫描,只要是符合≤t的就符合,如果扫描到该叶子节点的尾部,则跳到它的右兄弟页节点。数据库的页中会保存左、右兄弟的节点指针。重复这样的执行过程,直到元组的索引键值超过上限t或者最后一个叶子节点被处理完。

     当然,如果是降序生成元组,其处理过程也是一样的,只不过是按上限到下限的顺序进行处理。

 

3.B树上的插入操作

 为了便于问题的描述,现重新构造一个只有两层的B树。见图2。

  简单插入操作: 
   参考图2,先考虑一个简单的操作,向该B树插入一条索引键值为9的记录。执行流行如下:

     1 )执行索引键值=9的查找操作,确定该新记录应该插入到叶子节点L1中。
     2 )此时发现叶子节点L1中还是有空闲记录空间的,因此可以确定该新记录可以插入L1中而不会导致分裂。
     3 )将记录10、16向后移动移动一个位置,插入索引键值为9的新记录。插入之后,8、9、10、16还是顺序的。
   经过此插入操作之后,新的B树见图3。

     

 

   复杂插入操作:
   参加图3,现在继续插入索引键值为13的记录。执行流程如下:
   1 )执行索引键值=13的查找操作,确定该新记录应该插入到叶子节点L1中。
   2 )此时发现叶子节点L1中已经没有足够的空间来容纳新的记录,此时需要进行分裂节点的操作。

   3)分配一个新的叶子节点页L3,将满页L1中的后一半数据移入L3中。重新设置叶子节点的左右兄弟指针。参见图4。

 

 

 

 

 4 )叶子节点 L3 虽然生成了,但是上层索引节点用还没有相应的指针指向它。因此需要在索引节点 I1 增加一个索引项:索引键值为 10 、指针指向叶子节点 L3 。如果 I1 的空间不够,还会导致 I1 节点的分裂,当然此处未发生这种情况。参加图 5
 
 
 
 5)将索引键值=13的新记录插入到L3中,执行结束。见图6
 
 

 

 
4.B树上的删除元组操作
     假设 B 树的组织形式如图 7
 
    删除索引键值为 9 的记录,执行流程:
   1 )以索引键值 =9 查询 B 树,定位要删除的元组,该元组位于叶子节点 L1
   2 )删除索引键值 =9 的入口项, 10 16 对应的记录向前移动一个位置。参照图 8
     一般的文档上都会描述下溢节点,也就是说入口项占有率 <50% (一般的设为 50% ),就会与兄弟节点进行合并,从而使所有节点的最小占有率 50% 。这样做的好处是显而易见的,维持 B 树在合理的深度。但是这样可能频繁的合并、分裂操作。
   所以,大多数实际的 B 树不对下溢节点进行合并操作。
 
5.B树的更新操作
   B 树的更新操作,分为两种:
   1 )直接对数据进行更新;
   2 )分解为删除加插入操作。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值