B树的结构及效率

4.3 B树
虽然一级或两级索引通常有助于加快查询,但在商用系统中常使用一种更通用的结构。这
一通用的数据结构簇称为B树,而最常使用的变体称为B +树。实质上:
? B树能自动地保持与数据文件大小相适应的索引层次。
? 对所使用的存储块空间进行管理,使每个块的充满程度在半满与全满之间。这样的索引不
再需要溢出块。
在接下来的内容中,我们将讨论“ B树”,但具体细节都针对B +树这一变体。其他类型的B
树在习题中讨论。
4.3.1 B树的结构
正如其名称所暗示的那样, B树把它的存储块组织成一棵树。这棵树是平衡的,即从树根到
树叶的所有路径都一样长。通常B树有三层:根、中间层和叶,但也可以是任意多层。为了对B
树有一个直观的印象,可以先看一下图4 - 2 1、图4 - 2 2和图4 - 2 3,其中前两个图所示的为B树结点,
而后一个图所示的为一个小而完整的B树。

对应于每个B树索引都有一个参数n,它决定了B树的所有存储块的布局。每个存储块存放n
个查找键值和n+ 1个指针。在某种意义上讲, B树的存储块类似于4 . 1节讲述的索引块,只不过B
树的块除了有n个键-指针对外,还有一个额外的指针。在存储块能容纳n个键和n+ 1个指针的前
提下,我们把n取得尽可能大。
例4 . 1 9 假定我们的存储块大小为4 0 9 6字节,且整数型键值占4字节,指针占8字节。要是不
考虑存储块块头信息所占空间,那么我们希望找到满足4n+ 8 (n+ 1 )≤4 0 9 6的最大整数值n。这个
值是n = 340
。□

(注:innodb默认的索引页大小是16k,可以算出n是1364.)


下面几个重要的规则限制B树的存储块中能出现的东西:
? 根结点中至少有两个指针被使用。所有指针指向位于B树下一层的存储块。
? 叶结点中,最后一个指针指向它右边的下一个叶结点存储块,即指向下一个键值大于它的
块。在叶块的其他n个指针当中,至少有个指针被使用且指向数据记录;未使用
的指针可看作空指针且不指向任何地方。如果第i个指数被使用,则指向具有第i个键值的
记录。
? 在内层结点中,所有的n+ 1个指针都可以用来指向B树中下一层的块。其中至少
个指针被实际使用(但如果是根结点,则不管n多大都只要求至少两个指针被使用)。如果j
个指针被使用,那该块中将有j-1个键,设为K1,K2??,Kj - 1。第一个指针指向B树的一
部分,一些键值小于K1的记录可在这一部分找到。第二个指针指向B树的另一部分,所有
键值大小等于K1且小于K2的记录可在这一部分中。依此类推。最后,第j个指针指向B树的
又一部分,一些键值大于等于Kj - 1的记录可以在这一部分中找到。注意:某些键值远小于
K1或远大于Kj - 1的记录可能根本无法通过该块到达,但可通过同一层的其他块到达。
? 假若我们以常规的画树方式来画B树,任一给定结点的子结点按从左(第一个子结点)到
右(最后一个子结点)的顺序排列。那么,我们在任何一个层次上从左到右来看B树的结
点,结点的键值将按非减的顺序出现。


从技术上来讲,整个B树的块只有一个指针也是可能的,因为它可能是只有一个记录的数据文件的索引。在这种
情况下,整个B树既是根块又是叶块,且这个块只有一个键值和一个指针。在下面的描述中我们忽略这种平凡的
情况。


例4 . 2 0 在这个例子和其他B树实例中,我们设n= 3。也就是说,块中可存放3个键值和4个
指针,这是一个不代表通常情况的小数字。键值为整数。图4 - 2 1所示为一个完全使用的叶结点。
其中有三个键值5 7、8 1和9 5。前三个指针指向具有这些键值的记录。而最后一个指针,指向右
边键值大于它的下一个叶结点,这正是叶结点中通常的情况。如果该叶结点是序列中的最后一
个,则该指针为空。
叶结点不必全部充满,但在我们这个例子中, n= 3,故叶结点至少要有两个键-指针对。也
就是说,图4 - 2 1中的键值9 5和第三个指针可以没有,该指针标有“至键值为9 5的记录”。


图4 - 2 2所示为一个典型的内部结点。其中有三个键值,与我们在叶结点的例子中所选的一样:
5 7、8 1和9 5 。该结点中还有四个指针。第一个指针指向B树的一部分,通过它我们只能到达键
值小于第一个键值即5 7的那些记录。第二个指针通向键值介于该B树块第一个键值和第二个键值
之间的那些记录,第三个指针对应键值介于该块第二个键值和第三个键值之间的那些记录,第
四个指针将我们引向键值大于该块中第三个键值的那些记录。
同叶结点的例子一样,内部结点的键和指针槽也没有必要全部占用。不过,当n= 3时,一个
内部结点至少要出现一个键和两个指针。元素缺失最极端的情形就是键值只有5 7,而指针也仅
使用前两个,在这种情况下,第一个指针对应于小于5 7的键值,而第二个指针对应于大于等于
5 7的键值。键值□


例4 . 2 1 图4 - 2 3所示为一棵完整的三层B +树;其中使用例4 . 2 0中所描述的结点。我们假定
数据文件的记录的键是2~4 7之间的所有素数。注意,这些值在叶结点中按顺序出现一次。所有
叶结点都有两个或3个键-指针对,还有一个指向序列中下一叶结点的指针。当我们从左到右去
看叶结点时,所有键都是排好序的。
根结点仅有两个指针,恰好是允许的最小数目,尽管至多可有4个指针。根结点中的某个键
将通过第一个指针访问到的键值与通过第二个指针访问到的键值分隔开来。也就是说,不超过
1 2的键值可通过根结点的第一个子树找到;大于等于1 3的键值可通过第二个子树找到。


虽然键值一样,但图4 - 2 1所示的叶结点与图4 - 2 2所示的内部结点之间并没有什么联系。事实上,它们不可能出现
在同一棵B树中。
记住本节讨论的所有B树都是B+树,但在以后提到时我们将省略“+”号。

 

 

4.3.7 B树的效率
B树使我们能实现记录的查找、插入和删除,而每个文件操作只需很少的磁盘I / O。首先我
们注意到,如果每个块容纳的键数n相当大,比如1 0或更大,那么,分裂或合并块的情况将会很
少。此外,这种操作必需时,绝大多数时候都被局限在叶结点,因此只有两个叶结点和它们的
父结点受到影响。所以,我们基本上可以忽略B树重组的I / O开销。
然而,每次按给定查找键值查找记录都需要我们从根结点一直访问到叶结点以找到指向记
录的指针。因为我们只读B树的块,所以磁盘I / O数将是B树的层数加上一次(对查找而言)或两
次(对插入或删除而言)处理记录本身的磁盘I / O。我们肯定会这样问: B树到底有多少层?对
于典型的键、指针和块大小来说,三层就足够了,除非数据库极大。因此,我们一般取3作为B
树的层数。下面的例子说明了其原因。


例4 . 2 7 回忆一下我们在例4 . 1 9中的分析,我们当时确定每块可容纳示例数据的3 4 0个键-指
针对。假若一般的块充满度介于最大和最小中间,即一般的块有2 5 5个指针。一个根结点,有
2 5 5个子结点,有2 5 52= 6 5 0 2 5个叶结点;在这些叶结点中,我们可以有2 5 5的立方,即约1 . 6 6×1 0的7次方个指向记录的指针。也就是说,记录数小于等于1 . 6 6×1 0的7次方 (一千六百万行)文件都可以被3层的B树容纳。□

(注:在innodb中,低于1/2就会合并,所以如果按(1364/2)的来算,3层的B树在innodb中至少可容纳682的3次方约合 31.72千万行记录的键)


不过,对于每次查找,我们甚至可以通过B树用比3次还少的磁盘I / O来实现。B树根结点块
是永久地缓存在主存中的绝佳选择。如果这样,那么每次查找3层的B树只需两次磁盘读操作。
实际上,在某些情况下,把B树的第二层结点块保存在缓冲区中也是合理的。这样, B树的查找
就减少到一次磁盘I / O再加上处理数据文件本身所需的磁盘I / O。


如果我们看根结点的第一个具有键值7的子结点,会发现它有两个指针,一个通向小于7的键,
而另一个通向大于等于7的键。注意,该结点的第二个指针只能使我们找到键7和11,而非所有大
于7的键,比如键1 3(虽然我们可以通过叶结点中指向下一个块的指针找到那些更大的键)。
最后,根结点的第二个子结点的4个指针槽都被使用。第一个指针将我们引向一些键值小于
2 3的键,即1 3、1 7和1 9。第二个指针将我们引向键值大于等于2 3而小于3 1的所有键;第三个指
针将我们引向键值大于等于3 1而小于4 3的所有键;而第四个指针将我们引向一些键值大于等于
4 3的键(在这个例子中,是所有的键)。


转载于:https://my.oschina.net/u/1866821/blog/297670

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值