在平常的开发过程中,对于千万级的数据库中,不添加索引的查询是非常慢的,使用主键进行查询时,可以看出非常快,其实这就是使用了主键索引。那么,索引的底层到底是怎么实现的,在这里做一个记录。

一、索引是什么

一般情况我们,我们都将索引形容成是一本书的目录,其实这是在说通过索引可以快速的查找到我们想要的数据,索引底层的具体实现其实不是这么简单的。

首先我们明确索引是帮助Mysql(数据库)高效获取数据的排好序的数据结构

索引数据结构:二叉树、红黑树、Hash表、B-Tree,在Mysql数据库中的索引有两大类,Btree(B+Tree)和Hash

mysql 索引覆盖 mysql索引底层实现_数据结构


(1)Btree方式(Mysql数据库99%的索引都是使用了这种方式)

在Mysql数据库中,Mtree方式是使用B+Tree实现的,B+Tree也是通过二叉树、红黑树、B-tree一步一步演变实现的的。

1.二叉树:在二叉树中左子树的值都小于根节点的值,右子树的值都大于根节点,但这样就会存在一个问题,当一串数组按照有序数列,存到二叉树中时,就会形成链表样式的数据,查询效率很低。

2.红黑树:是二叉树的进阶版,也叫二叉平衡树,它的出现就可以防止数据在存储时出现向二叉树那样的链式结构。当遇到千万级的数据量时,红黑树的层级还是比较大的,这样在查询时还是会消耗大量的时间。

3.B-Tree:当遇到千万级的数据量时,红黑树是无法满足要求的,我们需要减少红黑树的层级深度,那就需要增加其每一层的广度(即增加叶子结点的个数),这就需要一个结点上存放多个索引元素(这样就会形成多个分支,从而增加叶子结点的个数)

mysql 索引覆盖 mysql索引底层实现_二叉树_02


由于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;叶子节点不存储指针。

mysql 索引覆盖 mysql索引底层实现_二叉树_03


一般在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增加了顺序访问指针。

mysql 索引覆盖 mysql索引底层实现_数据库_04


在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。做这个优化的目的是为了提高区间访问的性能,例如上图中如果要查询key为从18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率。

(2)Hash方式

与哈希算法相同,通过将数据变成固定的分散数据进行存储,这种方式在查询数据时的效率很高,但在Mysql数据库中使用这种方式的索引的很少,原因在于这种方式不支持范围查找,但在大多数的数据表添加索引时,使用的时候都会存在范围查找,这种方式就很难实现快速高效的查询了,而BTree的B+Tree则很好的实现了这一问题。

下一节 : 数据库索引二之MyISAM和InnoDB数据存储引擎中索引的架构实现