索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据。索引在mysql数据库中分三类:B+树索引、Hash索引、全文索引。
一、二叉树索引
二叉树节点中存储了键(key)和数据(data)。二叉查找树的特点就是任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值。顶端的节点我们称为根节点,没有子节点的节点我们称之为叶节点。
- 二叉树查询:查找一个key的data
- 首先将根节点作为当前节点,把key与当前节点的右子节点的键值key1相比,如果key>key1,那么把当前节点下的右子节点作为新的当前节点,否则就把当前节点下的左子节点作为新的当前节点;
- 重复以上过程,直到找到与key相等的键值,取出data;
- 平衡二叉树:如果二叉树的子节点全为右或全为左,形成一个单独的斜枝,其查找效率与全表扫描无异,此时就需要平衡二叉树(AVL)了。
- 平衡二叉树:在满足二叉树查找树特征的基础上,要求每个节点的左右子树的高读差不能超过1;
- 平衡二叉树保证了树的构造是平衡的,当我们插入或删除数据导致不满足平衡二叉树时,平衡二叉树会进行调整树上的节点来保持平衡。
二、B树
因为内存的易失性,一般情况下,我们都会选择将数据和索引存储在磁盘这种外围设备中。但是和内存相比,从磁盘中读取数据的速度会慢上百倍千倍甚至万倍,所以,我们应当尽量减少从磁盘中读取数据的次数,另外,从磁盘中读取数据时,都是按照磁盘来读取的,并不是一条一条读的。如果我们把尽量多的数据放进磁盘中,那一次磁盘读取操作就会读取更多的数据,那么我们找数据的时间也会大幅度降低;如果我们用树这种结构作为索引的数据结构,那我们每查找一次数据就需要从磁盘中读取一个节点,也就是我们说的一个磁盘块。我们都知道平衡二叉树可是每一个节点只存储一个键值和数据的,那就说明每个磁盘块仅仅存储一个键值和数据!那如果要存储海量的数据呢,可想而知,二叉树的节点将会非常多,高度也会及其高,我们查找数据时也会进行多次磁盘IO,我们查找数据的效率将会极低!
在innodb中,数据页通过双向链表连接以及叶子节点中数据之间通过单项链表连接的方式可以找到列表中所有的数据。
- B树:为了解决平衡二叉树的弊端,我们应该寻找一种单个节点可以存储多个键值和数据的平衡树,也就是B(balance)树。
- B树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子节点,子节点的个数一般称为阶。基于这个特性,B树查找数据读取磁盘的次数将会很少,数据的查找效率也会比平衡二叉树高很多;
- B+树
- B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点不仅存储键值,也会存储数据。之所以这么做是因为在数据库中页的大小是固定的,innodb中页的默认大小是16KB。如果不存储数据,那么就会存储更多的键值,相应的树的结束(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数就会再次减少,数据查询的效率也会更快。另外,B+树的阶数是等于键值的数量的,如果我们的B+树一个节点可以存储1000个键值,那么3层B+树可以存储1000*1000=10亿个数据。一般根节点是常驻内存的,所以一般我们查找10亿数据,只需要2次磁盘IO。
- 因为B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而B树因为数据分散在各个节点,要实现这一点是很不容易。