我们都知道数据库中常用的优化慢查询的方式是:加索引。什么是数据库的索引呢?我们知道,最基本的查询算法当然是顺序查找,当然这种时间复杂度为O(n)的算法在数据量很大时显然是糟糕的,于是有了二分查找、二叉树查找等。但是二分查找要求被检索数据有序,而二叉树查找只能应用于二叉查找树,但是数据本身的组织结构不可能完全满足各种数据结构。所以,在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。哪些数据结构是可以提高查询速度的呢?哈希表、二叉树、B树、B+树等等都可以。目前大部分数据库系统及文件系统都采用B-Tree和B+Tree作为索引结构,为什么呢?
首先来看看哈希表。当我们采用哈希表来存储一些数据的时候,数据的存储位置是通过哈希算法随机算出来的,所以有可能出现哈希冲突。最终存储的数据将会没有顺序,那么对于这样一个索引结构,现在来执行下面的sql语句:
select * from student where name='小白'
可以直接对‘小白’按哈希算法算出来一个数组下标,然后可以直接从数据中取出数据并拿到锁对应那一行数据的地址,进而查询那一行数据。 那么如果现在执行下面的sql语句:
select * from student where name>'小白'
则无能为力,因为哈希表的特点就是可以快速的精确查询,但是不支持范围查询,所以哈希表不适合作为索引结构。
然后来看二叉树。我们知到二叉树的查找时间复杂度是O((log2N),查找效率与深度相关,而普通的二叉树可能由于内部节点排列问题退化成链表,这样查找效率就会很低。因此平衡二叉树是更好的选择,因为它保持平衡,即通过旋转调整结构保持最小的深度,其查找的时间复杂度也是O(log2N)。但实际上,数据库中索引的结构也并非AVL树或更优秀的红黑树,尽管它的查询的时间复杂度很低。
为什么平衡二叉树也不适合作为索引呢?索引是存在于索引文件中,是存在于磁盘中的。因为索引通常是很大的,因此无法一次将全部索引加载到内存当中,因此每次只能从磁盘中读取一个磁盘页的数据到内存中。而这个磁盘的读取的速度较内存中的读取速度而言是差了好几个级别。注意,我们说的平衡二叉树结构,指的是逻辑结构上的平衡二叉树,其物理实现是数组。然后由于在逻辑结构上相近的节点在物理结构上可能会差很远,每次读取的磁盘页的数据中有许多是用不上的。因此,查找过程中要进行许多次的磁盘读取操作。而适合作为索引的结构应该是尽可能少的执行磁盘IO操作,因为执行磁盘IO操作非常的耗时。平衡二叉树没能利用好磁盘预读的提供的数据,且树深度大(较B树而言),所以进行的磁盘IO操作更多。因此,平衡二叉树并不适合作为索引结构。
接下来看看B-Tree,B- tree 就是B树,简称平衡树。平衡二叉树没能充分利用磁盘预读功能,而B树是为了充分利用磁盘预读功能来而创建的一种数据结构,可以说B树就是为了作为索引才被发明出来的。
B树的每个节点可以存储多个关键字,它将节点大小设置为磁盘页的大小,充分利用了磁盘预读的功能。每次读取磁盘页时就会读取一整个节点。也正因每个节点存储着非常多个关键字,树的深度就会非常的小。进而要执行的磁盘读取操作次数就会非常少,更多的是在内存中对读取进来的数据进行查找。B树的查询,主要发生在内存中,而平衡二叉树的查询,则是发生在磁盘读取中。因此,虽然B树查询查询的次数不比平衡二叉树的次数少,但是相比起磁盘IO速度,内存中比较的耗时就可以忽略不计了。因此,B树更适合作为索引。
最后来看看更适合作为索引的B+Tree,MySQL中也是使用B+树作为索引。它是B树的变种,因此是基于B树来改进的。为什么B+树会比B树更加优秀呢?来看看两者的结构特点:
B树:有序数组+平衡多叉树;
B+树:有序数组链表+平衡多叉树;
B+树的关键字全部存放在叶子节点中,非叶子节点用来做索引,而叶子节点中有一个指针指向一下个叶子节点。做这个优化的目的是为了提高区间访问的性能。而正是这个特性决定了B+树更适合用来存储外部数据。
引用 走进搜索引擎 的作者梁斌老师针对B树、B+树给出的意见(为了真实性,特引用其原话,未作任何改动): “B+树还有一个最大的好处,方便扫库,B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持范围查找非常方便,而B树不支持。由于在数据库中基于范围的查询是非常频繁的,因此MySQL最终选择的索引结构是B+树而不是B树。
本文参考和整合了这篇博文:
https://blog.csdn.net/weixin_30531261/article/details/79312676