前言
这个地方我们简单说一下索引的什么数据结构才是最好的,直接给出结论:1.能在尽可能少的磁盘的I/O操作中完成查询工作。2.要能高效的查询某一个记录,也要能高效地执行范围查找。
一、什么是B+树?
B+其实就是B树的升级版,B树本质上是一个二叉树,具体而言就是一个平衡二叉树。而它们也有区别。
- B+的叶子节点(最底部的节点)才会存放实际数据(索引+记录),非叶子节点只会存放索引;
- 所有的索引都会在叶子结点出现,叶子结点构成一个有序表;
- 非叶子结点的索引也会同时出现在子节点中,并且是在子节点中索引的最大处或最小处;
- 非叶子节点中有多少个子节点,就有多少个索引;
二、B+树与B树的性能比较;
1.单点查询
- B树在查询时,由于B树里的叶子结点和非叶子结点里面存放索引又存放数据,所以有时候访问到非叶子结点可以找到数据,有时候访问到叶子结点可以找到数据,查询波动会比较大。
- B+树的非叶子节点不存放实际的数据记录,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的B树,B+树可以存放更多的索引,因此B+树比B树更加矮胖,查询底层结点的磁盘I/O次数会更少。
2.插入和删除效率
由于B+树有大量的荣誉结点,这样使得删除一个结点的时候,可以直接从叶子结点删除,甚至可以不动非叶子结点,这样删除非常快。B+树在删除根结点的时候,由于存在冗余结点,所以不会发生复杂的树变形。而B树不同,B树没有冗余结点,所以删除的时候会发生复杂的树变化。插入也是一样,最多涉及树的一条路径,B+树会自动平衡,不需要更多复杂的算法。
3.范围查询
B 树和 B+ 树等值查询原理基本一致,先从根节点查找,然后对比目标数据的范围,最后递归的进入子节点查找。
因为 B+ 树所有叶子节点间还有一个链表进行连接,这种设计对范围查找非常有帮助,比如说我们想知道 12 月 1 日和 12 月 12 日之间的订单,这个时候可以先查找到 12 月 1 日所在的叶子节点,然后利用链表向右遍历,直到找到 12 月12 日的节点,这样就不需要从根节点查询了,进一步节省查询需要的时间。
总结
树的高度决定于磁盘 I/O 操作的次数,因为树是存储在磁盘中的,访问每个节点,都对应一次磁盘 I/O 操作,也就是说树的高度就等于每次查询数据时磁盘 IO 操作的次数,所以树的高度越高,就会影响查询性能。
MySQL 默认的存储引擎 InnoDB 采用的是 B+ 作为索引的数据结构,原因有:
- B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树,B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
- B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;
- B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。