索引-02
一、索引结构B树、B+树分析
B树:以一个m阶树为例:
- 每个结点至多拥有m棵子树;
- 根结点至少拥有两颗子树(存在子树的情况下);
- 除了根结点以外,其余每个分支结点至少拥有 m/2 棵子树;
- 所有的叶结点都在同一层上;
- 有 k 棵子树的分支结点则存在 k-1 个关键码,关键码按照递增次序进行排列;
- 关键字数量需要满足ceil(m/2)-1 <= n <= m-1;
B树有磁盘预读功能,每一个磁盘块一次io操作。减少io操作,提高查询效率。
B树的关键字全部存放在树本身中,不存放在叶子节点上。叶子节点可以看成是一个外部节点,不保存任何信息。叶节点之间没有指针相连接。
B+树:
同样的,以一个m阶树为例:
- 根结点只有一个,分支数量范围为[2,m];
- 每个结点包含分支数范围为[ceil(m/2), m];
- 分支结点的关键字数量等于其子分支的数量减一,关键字的数量范围为[ceil(m/2)-1, m-1],关键字顺序递增;
- 所有叶子结点都在同一层;
B+树相比如B树来说,所有的关键字都会出现在叶节点上,并且每个节点之间通过指针相连。可以加快查找速度。
叶结点中存放索引值、指向记录的指针、指向下一个叶结点的指针。叶结点内的索引值是记录中键的拷贝,这些索引值以排好序的形式,从左到右分布在叶节点中。
二、为什么B树、B+树适合为索引结构
数据库文件一般级别非常大,内存没有足够的空间去存储,所以数据库的数据都存放在硬盘(磁盘)中。在查找时,不论是全表扫描还是利用索引,都是整块整块(页)的的读取到内存中,当内存不足的时候内存会被及时的释放,否则会出现内存泄露的错误。
之所以会选择B树和B+树作为索引结构,是因为这两种结构具有磁盘预读功能,每次读取一定量的数据,这样极大的减少了磁盘IO。将一个节点的大小设为等于一个页,每一页包含多个数据,这样每个节点只需要一次I/O就可以完全载入。
B树最大的功能就是磁盘预读功能。
由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:
当一个数据被用到时,其附近的数据也通常会马上被使用。
程序运行期间所需要的数据通常比较集中。
由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。
三、为什么B+树比B树更加适合作为索引结构
结构上:B树的关键字都存放在树中,而B+树所有的关键字都会顺序的出现在叶节点上,并且叶节点之间通过指针相连。而正是这个特性决定了B+树更适合用来存储外部数据。
举例说明:比如要查 5-10之间的,B+树一把到5这个标记,再一把到10,然后串起来就行了,B树就非常麻烦。
性能上:B树只能做随机查询,B+除了随机查询,还可以做顺序查询。
B+树的磁盘读写代价更低。B+树的内部结点并没有指向关键字具体信息的指针(B+树中非叶节点只包含索引域不包含data域)
,其内部结点比B树小,盘块能容纳的结点中关键字数量更多,一次性读入内存中可以查找的关键字也就越多,相对的,IO读写次数也就降低了。而IO读写次数是影响索引检索效率的最大因素。
-
B+树的查询效率更加稳定。B树搜索有可能会在非叶子结点结束,越靠近根节点的记录查找时间越短,只要找到关键字即可确定记录的存在,其性能等价于在关键字全集内做一次二分查找。而在B+树中,顺序检索比较明显,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有关键字的查找路径长度相同,导致每一个关键字的查询效率相当。
- B+树只要遍历叶子节点就可以实现整棵树的遍历。
四、为什么不使用平衡二叉树、以及红黑树作为索引
我们说的平衡二叉树结构,指的是逻辑结构上的平衡二叉树,其物理实现是数组。然后由于在逻辑结构上相近的节点在物理结构上可能会差很远。因此,每次读取的磁盘页的数据中有许多是用不上的。因此,查找过程中要进行许多次的磁盘读取操作。 所以磁盘IO的次数会增多。