数据结构与算法-----13.Mysql数据库索引是如何实现的:

1.我们在软件开发过程中,为了提高数据库的查询效率,通常的做法是给数据库表中的某一个字段构建索引。有时候需要思考一下:数据库的索引是如何构建的呢?它的底层使用了什么数据结构?

2.我们首先确定一下数据库索引的需求:(1)根据某个值查找数据:select * from user where uid = 1234;

(2) 根据某个区间查找数据集合:select * from user where uid>1234 and uid<4567;

除此之外,我们还需要考虑索引的性能问题,因为我们创建索引的目的就是提高查询效率的,性能问题主要从时间和空间考虑。

3.尝试用学过的知识来解决这个问题:

支持快速查询,插入,删除操作的动态数据结构有 散列表,平衡二叉查找树,跳表。那么它们是否适合构建索引呢?

散列表:它查询的性能很好,时间复杂度为O(1),但是由于它内部存储的数据是无序的,所以它不支持区间查找。不可选。

平衡二叉查找树:查询性能也很好,时间复杂度为O(logn),但是它仍然不支持按照区间查找。不可选。

跳表:它是通过在链表的基础上构建索引层,查询的时间复杂度为O(logn),它也支持按照区间进行查找。只需要根据索引在链表中找到区间的首节点,然后遍历链表到区间的尾节点即可。

但是Mysql中的索引并不是使用跳表这种数据结构来解决的,而是使用B+树这种数据结构(个人感觉可能是B+树这种数据结构诞生比跳表早)

4.B+树的演进过程:

4-(1)其实B+树这种数据结构与跳表比较相似,但它是通过二叉查找树演进过来的。为了让二叉查找树可以按照区间查找,我们的做法是:二叉查找树的非叶子节点不存储数据本身,只作为索引使用数据本身都存储在二叉查找树的叶子节点,然后将叶子节点用一个双向链表串联在一起,并且链表中的数据是从小到大有序排列。这样就可以做到利用二叉查找树来加快查找速度,然后利用双向链表来进行数据的区间查找。例图如下:

如果我们需要查找某一个区间的数据集合,那么我们可以根据区间的起始值通过二叉查找树,找到叶子节点。然后再顺序遍历链表,直到节点中的数据值等于区间的终止值为止。

4-(2).二叉查找树产生的瓶颈问题:

利用双向链表的方式,让我们解决了数据库中按照区间查找数据集的问题。那么当我们为几千万条数据甚至上亿条数据构建索引时,为了保证索引的效率,我们就会把构建好的索引树存储到内存中。但是这样的方法对内存的消耗是很大的,例如:我们为一亿条数据构建索引,那么索引树中大约会包含一亿个节点,如果每个节点的大小按照16个字节来结算,那么大约需要占用1G的内存空间,如果有10张这样的数据表,那么就需要10G的内存空间。再实际的软件开发中是不可取的。

为了减少内存的消耗,我们可以通过以时间换空间的方式:将索引树存储到硬盘中。通常情况下,内存的访问速度是纳秒级别的,硬盘的访问速度是毫秒级别的。势必查询性能会产生影响。

将索引树存储到硬盘中以后,那么每个节点的读取或访问,都是一次I/O操作,树的高度就等于每次查询数据时I/O操作的次数。所以为了提高查询的效率,就必须要降低树的高度。

问题:如何将树的高度降低呢:

原始的树是二叉,那么我们可以将它变成m叉的树形结构。高度降低了,I/O次数减少了,查询的效率也就提高了。虽然说树的高度越低(m值越大),查询数据时I/O操作的次数就越来越少了,但是也不是m得值越大越好。因为操作系统每执行一次I/O操作,读取得是一页数据(大小为4k),那么如果二叉查找树中一个节点存储得数据量过大,会引发多次操作。综上所述:我们最好的方法应该是尽可能保证一个节点中保存的数据在一页数据大小(4K左右)。根据索引查找数据示意图:

4-(3) Mysql索引的更新过程:

作为一名软件工程师,我们需要直到,索引对我们有利也有弊。利:可以提高数据的查找效率。弊:会降低数据的写入效率。

原因:当我们插入数据时,索引树会进行更新。mysql使用B+树构建索引树的时候,树的分支m是根据数据页预先计算好的。每个节点的子节点数不能大于M。

当有数据插入时,有可能某一个节点下的子节点数会大于M,为了不大于M,所以就需要把当前节点进行分裂操作。分裂之后,有可能当前节点的父节点的子节点个数就大于M了,同样采取分类操作,分类操作是自上而下的。示意图如下:

当有数据删除时,某个节点的子节点个数就会减少,B+Tree中有一个阈值=m/2,如果某个节点的子节点个数小于m/2,那么就会将当前节点和它的兄弟节点合并。如果合并之后的子节点总数大于了M,那么再进行分裂操作。示意图如下:

4-(4)总结B+TRee:

B+Tree就是通过存储再磁盘上的多叉树,实现时间和空间上的平衡,既保证了查询效率,有节省了内存空间。B+Tree的每个节点的子节点数量不得大于M,也不能小于m/2,但是根节点除外。一般根节点存储在内存中,子节点存储在磁盘中。

5. B-Tree:

其实B-Tree就是B+Tree的降级版本,他与B+Tree的最大区别是:

(1) B-Tree的非叶子节点存储数据,B+Tree的非叶子节点不存储数据。

(2)B-Tree的叶子节点不需要链表串联,所以他只是一个子节点大于M/2,小于M的M叉树。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章