2022-10-27 367
你是不是对于 MySQL 索引的知识点一直都像大杂烩,好像什么都知道,如果进行深究的话可能一个也答不上来。
图片来自 Pexels
假如你去面试,面试官让你聊一下对索引的理解,然而你对索引的理解仅限于,检索数据就是快,是一种数据结构这个层面,那你就只能回家等通知了。
为了避免这种尴尬的事情发生,咔咔用时两天将索引的内容在自己理解的范围内进行了整理,如有整理不全面的地方可以在评论区进行补充和提建议。
MySQL 索引到底是什么
相信大多数伙伴都买过技术类的书籍,看完没看完不知道,但是目录肯定看的次数最多。
看目录有没有自己目前的痛点,如果有就会根据目录对应的页码用最快的速度翻阅到相应内容位置。
那么在 MySQL 中同样也是这样的一个道理,MySQL 的索引就是存储引擎为了快速找到数据的一种数据结构。
同样在 MySQL 索引中又分了几种类型,分别为:
下文所有内容均在 InnoDB 的基础上讨论。
为什么要使用索引
①索引可以加快数据检索速度,这也是使用的索引的最主要原因。
②索引本身具有顺序性,在进行范围查询时,获取的数据已经排好了序,从而避免服务器再次排序和建立临时表的问题。
③索引的底层实现本身具有顺序性,通过磁盘预读使得在磁盘上对数据的访问大致呈顺序的寻址,也就是将随机的 I/O 变为顺序 I/O。
这几点不理解就暂时先放着,继续看下文即可,会给你一个满意的解释。
任何事物都存在双面性,既然能提供性能的提升,自然在其他方面也会付出额外的代价:
InnoDB 为什么使用 B+Tree 而不使用 BTree
聊到这个问题那就必须得分清楚 BTree、B+tree 的区别,首先来看一下 BTree。
Btree 解析
先来看一下 BTree 的数据结构是怎么样的,这里咔咔给提供一个网站地址,可以看到关于数据结构的一些实现过程:
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
先来看 BTree 的数据结构,下图是咔咔已经将数据填充进去的:
这里有一个陌生区关于 Max. Degree,这个你可以理解为阶,也可以理解为度。
例如现在这个值设置的是 4,那么在一个节点中最多就可以存储 3 条数据,设置为 5那就可以最多放 4 条记录。
现在可以看到目前只插入了 3 条数据:
那么再加一条数据,节点就会进行分裂,这个也就验证了当阶设置为 n 时,一个节点可存 n-1 条数据。
那接着再来插入几条数据看看:
想要达到快速检索数据,那就需要满足俩个特性,一个是有序,另一个就是平衡。
从下图中可以看到 BTree 是有一定的顺序性的,平衡性更满足,可以看上文中生成的第一张图。
那么在 BTree 中找一个值是怎么找呢?例如现在要找一个值 9,看一下寻找过程。
首先看到的数据是 4,9 是大于 4 的,所以会往 4 的右节点寻找。继续找到范围在 6 到 8 的节点,9 又大于 8,所以还需要往右节点寻找。
最有一步就找到了数据 9,这个过程就是 BTree 数据结构查找数据的执行过程。
了解到了 BTree 的数据结构后,我们在来看看在 MySQL 中关于 BTree 是如何存储的。
在下图中 P 代表的是指针,指向的是下一个磁盘块。在第一个节点中的 16、24 就是代表我们的 key 值是什么。date 就是这个 key 值对应的这一行记录是什么。
那么此时想要寻找 key 为 33 的这条记录应该怎么找。33 在 16 和 34 中间,所以会去磁盘 3 进行寻找。
在磁盘 3 中进行判断,指针指向磁盘 8。在磁盘 8 中即可获取到数据 33,然后将 data 返回。
那么在这个过程中到底读取了多少条数据呢?在计算之前需要先了解一些知识点。
从 MySQL 5.7 开始,存储引擎默认为 innodb,并且 innodb 存储引擎用于管理数据的最小磁盘单位就是页。
这个页的类型也分为好几种,分别为数据页,Undo 页,系统页,事物数据页。
一般说到的页都是数据页。默认的页面大小为16kb,每个页中至少存储2条或以上的行记录。
那么根据 BTree 数据查找的过程中可以得知一共读取了三个磁盘,那么每个磁盘的大小就是 16kb。
而目前的给的案例寻找了三层,那么三层存储的数据就是:16kb*16kb*16kb=4096kb。
如果按照一条记录所需内存 1kb,那么这三层的 BTree 就可以存储 4096 条记录。
各位数据库的数据少则几百万,多则几千万数据,那么 BTree 的层级就会越来越深,相对的查询效率也会越来越慢。
这个时候是不是应该思考一个问题,那就是为什么在 Btree 中 48kb 的内存怎么就只能存储 4000 多条记录?
问题就出现在 data 上,要知道在计算数据大小时指针地址和 key 的内存都是没有计算在内的,单单就计算了 data 的内存。
因为在 BTree 结构中,节点中不仅存储的有 key、指针地址还有对应的数据,所以就会造成单个磁盘存储的数据相对很少的原因。
为了解决单个节点存储数据量小的问题,于是就演变出另一种结构,也就是下文提到了 B+Tree。
B+Tree 解析
依然如初看一下 B+Tree 的数据结构。为了方便对比,将 BTree 和 B+Tree 的数据结构放到了一起。
那么可以看到在 B+Tree 中叶子节点是存放了全量的数据,而非叶子节点只存储了 key 值。
咦!这不是就很好的解决了 BTree 带来的问题吗?可以让每个节点存储更多的数据。每个节点存储的数据越多,那么相对的就是树的深度就不会过深。
了解到了 B+Tree 的数据结构后,我们在来看看在 MySQL 中关于 B+Tree 是如何存储的。
从上图很明显就可以看到两点不同:
那么在这个过程中到底读取了多少条数据呢?
如果说 B+Tree 读取数据的深度跟 B-Tree 的深度一样,都是三层,那么同样的道理每个磁盘的大小为 16kb。
那在 B+Tree 中非叶子节点可以存储多少数据呢!一般来说我们每个表都会存在一个主键。
根据三层来计算,第一层跟第二层存储的是 key 值,也就是主键值。
都知道 int 类型所占的内存时 4Byte(字节),指针的存储就给个 6Byte,一共就是 10Tybe,那么第一层节点就可以存储 16*1000/10=1600。
同理第二层每个节点也是可以存储 1600 个 key。
第三层是叶子节点,每个磁盘存储大小同样安装 BTree 的计算一样,每条数据占 1kb。
那么在 B+Tree 中三层可以存储的数据就是 1600*1600*16=40960000。
从这点来看 B+Tree 存储的数据跟 BTree 存储的数据根本就不是一个级别。
所以可以得出结论:
Hash 索引
先来创建一个 hash 索引:
altertableuseraddindexhash_genderusinghash(gender);
存储引擎使用的是 innodb:
会发现 name 的索引类型还是为 Btree,在 innodb 上创建哈希索引,被称之为伪哈希索引,和真正的哈希索引不是一回事的,这点一定要明白。
在 Innodb 存储引擎中有一个特殊的功能叫做,自适应哈希索引,当索引值被使用的非常频繁时,它会在内存中基于 BTree 索引之上再创建一个哈希索引,那么就拥有了哈希索引的一些特点,比如快速查找。
哈希索引就是基于哈希表实现的,假设对 name 建立了哈希索引,则查找过程如下图所示,哈希表是根据键值对进行访问的数据结构,它让检索的数据经过哈希函数映射到散列表的对应位置,查找效率非常高。
哈希索引存储的是哈希值和行指针,没有存储 key 值、字段值,但哈希索引多数是在内存完成的,检索数据是非常快的,所以对性能影响不大:
B+Tree 跟 BTree 区别
经过了特别漫长的计算、画图现在基本对俩者的区别有一定认识了吧!
咔咔在这里进行总结一下:
B+Tree 适合做索引的原因
B+Tree 树非叶子节点只存储 key 值,因此相对于 BTree 节点可以存储更多的数据,每次读入内存的 key 值就更多,相对来说 I/O 就降低。
B+Tree 树查询效率稳定,任何数据的查找都是必须从叶子节点到非叶子节点,所以说每个数据查找的效率几乎都是相同的。
B+Tree 树的叶子节点存储的是全量数据,并且是有序的,所以说只需要遍历叶子节点就可以对所有的 key 进行扫描,在范围查找时效率更高。
原文链接:https://77isp.com/post/10294.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态