二叉树
概念:二叉树是另一种树形结构
特点:
- 每个结点至多只有两颗子树
- 二叉树的子树有左右之分
- 任何节点的左子节点均小于当前节点的值,右节点的值均大于当前节点的值
平衡二叉树
概念:平衡二叉树是基于二分法的策略提高数据的查找速度的二叉树的数据结构;
特点:
- 每个结点至多只有两颗子树
- 二叉树的子树有左右之分
- 任何节点的左子节点均小于当前节点的值,右节点的值均大于当前节点的值
- 树的左右两边的层级数相差不会大于1
- 没有值相等重复的节点
B树索引
概念:单一节点存储多个键值和数组的平衡树
特点:一个m阶的B树具有如下几个特征:
- 根结点至少有两个子女
- 除了根结点和叶子结点,其他结点至少有[ceil(m / 2)]个孩子,最多有m个孩子
- 若根结点不是叶子结点时,则至少有两个孩子
- 每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m
- 所有的叶子结点都位于同一层
- 每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划
- 节点中保存了key对应的所有数据
B数索引的数据结构如下图:
B+树索引
B+树和B树的进一步优化,如下图
根据上图可以看出B+树和B树有如下不同点:
- B+ 树非叶子节点上是不存储数据的,仅存储键值,而 B 树节点中不仅存储键值,也会存储数据。之所以这么做是因为在数据库中页的大小是固定的,InnoDB 中页的默认大小是 16KB。如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的 IO 次数又会再次减少,数据查询的效率也会更快。另外,B+ 树的阶数是等于键值的数量的,如果我们的 B+ 树一个节点可以存储 1000 个键值,那么 3 层 B+ 树可以存储 1000×1000×1000=10 亿个数据。一般根节点是常驻内存的,所以一般我们查找 10 亿数据,只需要 2 次磁盘 IO。
- B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。相邻之间的页用双向链表连接,叶子节点内的数据通过单向列表连接。通过链表的连接,mysql可以很轻松的做到排序和范围查找
B+树比B树更适合做文件索引的原因
结构上
- B树中关键字集合分布在整棵树中,叶节点中不包含任何关键字信息,而B+树关键字集合分布在叶子结点中,非叶节点只是叶子结点中关键字的索引;
- B树中任何一个关键字只出现在一个结点中,而B+树中的关键字必须出现在叶节点中,也可能在非叶结点中重复出现;
性能上(也即为什么说B+树比B树更适合实际应用中操作系统的文件索引和数据库索引?)
- 不同于B树只适合随机检索,B+树同时支持随机检索和顺序检索;
- B+树的磁盘读写代价更低。B+树的内部结点并没有指向关键字具体信息的指针,其内部结点比B树小,盘块能容纳的结点中关键字数量更多,一次性读入内存中可以查找的关键字也就越多,相对的,IO读写次数也就降低了。而IO读写次数是影响索引检索效率的最大因素。
- B+树的查询效率更加稳定。B树搜索有可能会在非叶子结点结束,越靠近根节点的记录查找时间越短,只要找到关键字即可确定记录的存在,其性能等价于在关键字全集内做一次二分查找。而在B+树中,顺序检索比较明显,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有关键字的查找路径长度相同,导致每一个关键字的查询效率相当。
- (数据库索引采用B+树的主要原因是,)B-树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。B+树的叶子节点使用指针顺序连接在一起,只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作(或者说效率太低)。