在平常的开发过程中,对于千万级的数据库中,不添加索引的查询是非常慢的,使用主键进行查询时,可以看出非常快,其实这就是使用了主键索引。那么,索引的底层到底是怎么实现的,在这里做一个记录。
一、索引是什么
一般情况我们,我们都将索引形容成是一本书的目录,其实这是在说通过索引可以快速的查找到我们想要的数据,索引底层的具体实现其实不是这么简单的。
首先我们明确索引是帮助Mysql(数据库)高效获取数据的排好序的数据结构。
索引数据结构:二叉树、红黑树、Hash表、B-Tree,在Mysql数据库中的索引有两大类,Btree(B+Tree)和Hash
(1)Btree方式(Mysql数据库99%的索引都是使用了这种方式)
在Mysql数据库中,Mtree方式是使用B+Tree实现的,B+Tree也是通过二叉树、红黑树、B-tree一步一步演变实现的的。
1.二叉树:在二叉树中左子树的值都小于根节点的值,右子树的值都大于根节点,但这样就会存在一个问题,当一串数组按照有序数列,存到二叉树中时,就会形成链表样式的数据,查询效率很低。
2.红黑树:是二叉树的进阶版,也叫二叉平衡树,它的出现就可以防止数据在存储时出现向二叉树那样的链式结构。当遇到千万级的数据量时,红黑树的层级还是比较大的,这样在查询时还是会消耗大量的时间。
3.B-Tree:当遇到千万级的数据量时,红黑树是无法满足要求的,我们需要减少红黑树的层级深度,那就需要增加其每一层的广度(即增加叶子结点的个数),这就需要一个结点上存放多个索引元素(这样就会形成多个分支,从而增加叶子结点的个数)
由于B-Tree的特性,在B-Tree中按key检索数据的算法非常直观:首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或找到null指针,前者查找成功,后者查找失败。B-Tree上查找算法的伪代码如下
BTree_Search(node, key) {
if(node == null) return null;
foreach(node.key)
{
if(node.key[i] == key) return node.data[i];
if(node.key[i] > key) return BTree_Search(point[i]->node);
}
return BTree_Search(point[i+1]->node);
}
data = BTree_Search(root, my_key);
B-Tree有许多变种,其中最常见的是B+Tree,例如MySQL就普遍使用B+Tree实现其索引结构。
4.B+Tree:内节点不存储data,只存储key;叶子节点不存储指针。
一般在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增加了顺序访问指针。
在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。做这个优化的目的是为了提高区间访问的性能,例如上图中如果要查询key为从18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率。
(2)Hash方式
与哈希算法相同,通过将数据变成固定的分散数据进行存储,这种方式在查询数据时的效率很高,但在Mysql数据库中使用这种方式的索引的很少,原因在于这种方式不支持范围查找,但在大多数的数据表添加索引时,使用的时候都会存在范围查找,这种方式就很难实现快速高效的查询了,而BTree的B+Tree则很好的实现了这一问题。