[数据库] 一文读懂Mysql数据库索引实现原理

咱们用了这么久Mysql数据库做项目,你知道数据是怎么存在数据库里吗?他们是如何存储的吗?

今天咱们就来扒一扒Mysql数据库索引的底层实现,Mysql数据库的索引是由都是由B+树实现的,那为什么不是其他的数据结构呢,比如二叉树,链表或者数组什么的?今天我们就来一探究竟。

0.前提

首先要想加快查找的速度,一个不管用什么存储,他的前提是一定要有序的,这个应该理解吧。如果数据的存储是无序的,任何数据类型的存储,在查找时都会降维成O(n),所以有序是大前提。

数组

先分析一下,数组是在内存怎么存储的?
思考一下


数组是在内存中连续存储的,它是有固定长度的,所以他不能扩容,初始申请的长度多长就是多长。因为连续存储,所以只要获取到数组的位置,你就知道了数组的所有元素的位置,这个应该理解吧?所以随机查询速度很快。但是如果你要是插入和删除元素的时候,因为内存的连续性,所以插入和删除时为了保持数组的特性(内存的连续性),就需要挪动元素。总的来说,数据插入和删除比较慢,查询比较快。但是作为数据库动辄百万千万的数据,插入一个数据,如果需要挪动百万次,这个数据库你觉得能用吗?

所以呢,数组Out!
在这里插入图片描述

链表

然后咱们再来看下链表
链表是怎么存储的?
思考一下



链表在内存里是不连续存储的,每一个链表元素都有一个指针(next),指向下一个元素的位置,即便链表的加强版双向链表,也只有你轮寻到它(要找的元素)的上一个或下一个元素,才知道它的位置。所以插入和删除是不用挪动了,但是查找又是大问题,要查找一个元素最慢要O(n/2).
所以呢,链表out!

二叉树

再来分析一下二叉树
二叉树是每个节点有零到两个子节点,并且左右节点是有序的,左边的都比根节点小,而右节点都比根节点大,这样每次查找都减少一半的无效数据,相当于二分查找,他的查找速度是O(log2 n),虽然他相对于其他的来说查找速度已经够快了,但是当进行范围查找时,他还是支持的不够好。离正确答案已经接近了,但还是有一段距离。

所以呢,二叉树,out!

那数据库到底怎么存在磁盘上,才能让查找速度又快,又支持范围查找呢?且听我娓娓道来。

思考下,数据库是如何存储呢?



因为数据库是可以持久化的,所以他一定是存储在硬盘上的,然而,从硬盘读取数据是相对内存来说是极度缓慢的,一次IO大概在9ms左右,它的成本大概是内存的10万倍。也正是因为磁盘IO的昂贵,所以操作系统对此做了优化,也就是预读;每一次可以读取一个数据时,他相邻的数据也一起读取出来。
看一下原理,局部预读原理:

当访问一个地址数据的时候,与其相邻的数据很快也会被访问到。每次磁盘IO读取的数据我们称之为一页(page)。一页的数据,根据操作系统不同,一页是4k或者8k。也就是说,每读一页时,就发生了一次IO。

也正是因为磁盘有预读机制的缘故,所以才能有进一步减少磁盘IO的可能性,也就是查询更快的可能,这里先卖个官司,请客官接着往下看。

磁盘的存储是线性内存地址(见图1)

图1
硬盘是由很多的内存空间组成的,内存空间是连续的,内存空间包含两部分,第一部分是内存地址,第二部分是当前内存的值。

1.非平衡二叉树

接着二叉树的分析

操作系统的内存是连续的存储的,寻址就是很耗时的,你可以把它理解成一个数组的,当我们对数组进行,查找的时候二分查找的速度应该是最快的,因为理论上每一次查找都能筛掉大概一半的无效的数据,二分查找就相当于非平衡二叉树查找,所以二分查找的速度会因为选择的中间变量的位置来决定。
图2
如果极端情况,会造成n次查找(见图3)。因为数据库要求稳定性,即每一次查找的速度都差不多。就好比如果你上某宝查询商品时,如果遇到一次这种情况,你就直接口吐芬芳了,随即怒卸之!所以为了让用户留下来,我们要让每次查找都差不多。
所以,非平衡二叉树,out!继续寻找。
图3

2.平衡二叉树

平衡二叉树(常用算法实现有红黑树),顾名思义,就是每个节点的两边比较平衡,它的特征是根节点是空树,或者每个节点的左右子树的节点数相差不超过1,因为当每次添加一条数据时,他就会添加一个子节点,然后他会自旋转,把左右子树调整为差值小于等于1,即每次查找的时间都是O( log2 N)。所以他的查找也比较稳定。因为一个箭头都是一次寻址过程,都比较耗时,并且如果总数据慢慢增多,查询效率下降的还是比较快。那怎么才能更快些呢?然后就有了B树。

图4

3.B树

每个节点只存一节点显然已经不能更快了,那怎么办呢?
B树来了,B树就是N阶二叉树,N阶限制的是每个节点最多有N个子树。然后因为每个节点能存多个值,N阶B树的特点就是,每个节点最多有N个子节点,并且每个节点可存多个值(这样设计,也是因为磁盘的预读机制,每次查一页数据),通过每个节点存多个值,所以树变得更矮胖,也就是IO次数更少,更快的查找到。当删除节点11时,就会自动左旋,让树变得平衡,以此来减少对比的次数,保证查询的速度最快。
图5
图6
查询速度已经很快了,但是如果你要进行范围查询就比较麻烦了。
比如要做查询该值大于3并且小于13的数据,如果用B树查找是这样的(图7)
1.要先找到3所在的位置
2.找到13算在的位置
3.找到3以后的元素,在回退到上一层,看有没有右节点,再回退上一层,再看看有没有右节点。
4.一直到13的位置的左节点的位置。
Ps.看看我这个10来条数据,来一个范围查找最少最少要5次IO,IO是很昂贵的,所以就有了B+树。

图7

4.B+树

B+树的特点是,所有data都存在叶子节点上,非叶子节点上不存data,只是做索引。然后叶子节点是一个连续的双向链表,树的深度没有增加,也就是查询速度没有变慢多少,但是它的范围查找时的速度是大大的提高。
图8
来看一下B+树的范围查找,还是刚才的查找
要做查询该值大于3小于13的数据,用B+树查找的步骤
1.查找到3的位置,一直往后,查到13停止

what?这TM也太快了吧!只要找到3所在的节点,就基本不需要IO了,飞一般的感觉!嗖嗖的!

总结

最后总结下,B+树是兼顾了查询的速度和范围查找的速度的终极产物,所以好多数据库的索引都使用了B+树来实现。

今天是大年初五,慕容田雨祝大家新春快乐,万事如意,阖家欢乐,鼠年大吉!
图9

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值