您现在的位置是:网站首页> 编程资料编程资料
图文并茂地讲解Mysql索引(index)_Mysql_
2023-05-26
504人已围观
简介 图文并茂地讲解Mysql索引(index)_Mysql_
前言
本篇文章相对来说篇幅较长,不是一会半会能看完的,建议您收藏起来慢慢看,关于索引的相关知识基本上都记录全了,通过这一篇文章足以让您的Mysql知识更上一层楼!
1. 索引概述
1.1 什么是索引?
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
想要学习好索引,那么就一定要掌握mysql的数据结构,其实在一提到数据结构,对于基础较差的来说,有时候是非常头疼的,不过在这里大家完全不用担心,接下来也会重点讲解数据结构,尽量会以白话文的形式叙述每一个数据结构!!!

1.2 使用索引和不使用索引的区别
在这里我们主要演示不使用索引和使用索引的区别到底有多大。
表结构及其数据如下:

假如我们要执行的SQL语句为 : select * from user where age = 45;
(1)无索引情况
在无索引情况下,就需要从第一行开始扫描,一直扫描到最后一行,我们称之为 全表扫描,性能很低。可能有的人该说了,明明在id为7的数据已经找到age为45的数据,为什么还是全表扫描呢?
因为对于mysql当中他并不知道后面是否还存在age为45的数据,所以他会不落下任何一条数据!

(2)有索引情况
如果我们针对于这张表的age字段建立了索引,假设索引结构就是二叉树,那么也就意味着,会对age这个字段建立一个二叉树的索引结构。而这个二叉树当中每个节点存储了真正数据的位置,我们只要在树当中找到了对应的age就意味着找到了真正的数据!
如下图:当查找age为45的时候,这时候会从根节点开始判断,根节点为36,比36大所以开始走右边的节点,光这一下子直接排除掉树的左边数据,然后又进行判断比48小,这时候走左边节点,然后就找到了,只需要扫描三次就可以找到数据了,极大的提高的查询的效率。

不管是二叉树还是B+树,一定都是有顺序的,他都是在新增数据的时候,根据数据的大小进行了排序然后分叉。也正因为如此,所以提高了查询速度!
备注: 这里我们只是假设索引的结构是二叉树,介绍一下索引的大概原理,只是一个示意图,并不是索引的真实结构,索引的真实结构,后面会详细介绍。
1.3 索引的特点

降低数据库的IO,什么是IO?
IO就是所谓的流,流又分为了读和写,当我们想要从文件当中找数据就需要读,当需要修改文件的时候就需要写,Mysql最终存储的数据都是在磁盘文件当中,那么我们想要找一条数据,怎么办呢?
先想想我们现实当中想要在一个文件找有没有哪个数据是怎么找的呢,直接打开文件,然后全局搜索,假如文件比较大的话,搜索也会有点卡顿。mysql他跟我们可不一样,我们那属于是人家windows系统给我们提供了这种便捷,我们可以直接打开文件,然后进行搜索。
mysql假如是全表扫描,首先需要从数据文件当中 将这张表的数据给全部读取到内存,然后再进行判断哪个数据是符合条件的。其中这也考验到了我们电脑的读的能力,当然越高配置的电脑读取速度越快。
假如加了索引,我们只需要将索引给读取出来,因为索引他指向了数据在文件上的地址。所以只需要找到对应数据的索引,然后通过索引获取到数据的位置,再从数据文件当中将这条数据给读取出来即可,也因此降低了IO成本。
如果数据集都读取到内存,假如电脑内存只有16G,而这张表有200G,一旦全表扫描,电脑岂不是直接挂掉了?
实际上,服务端并不需要保存一个完整的结果集。取数据和发数据的流程是这样的:
- 获取一行,写到 net_buffer 中。这块内存的大小是由参数 net_buffer_length 定义的,默认是 16k。
- 重复获取行,直到 net_buffer 写满,调用网络接口发出去。
- 如果发送成功,就清空 net_buffer,然后继续取下一行,并写入 net_buffer。
- 如果发送函数返回 EAGAIN 或 WSAEWOULDBLOCK,就表示本地网络栈(socket send buffer)写满了,进入等待。直到网络栈重新可写,再继续发送。
所以我们在使用过程,基本上不可能会因为mysql查询数据而导致服务器内存爆满,mysql主要是占用我们服务器的IO。
2. 索引结构
2.1 概述
MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种:

上述是MySQL中所支持的所有的索引结构,接下来,我们再来看看不同的存储引擎对于索引结构的支持情况。

注意: 实际开发当中会重点使用B+Tree,所以本篇我们也会重点讲解B+Tree的存储结构!我们平常所说的索引,如果没有特别指明,都是指B+Tree结构组织的索引。
2.2 二叉树
假如说MySQL的索引结构采用二叉树的数据结构,比较理想的结构如下:

如果主键是顺序插入的,则会形成一个单向链表,结构如下:
所谓的顺序就是恰好每次插入的都比上个节点小,或者大,这样就会形成一个链表

所以,如果选择二叉树作为索引结构,会存在以下缺点:
- 顺序插入时,会形成一个链表,查询性能大大降低。
- 大数据量情况下,层级较深,检索速度慢。
此时大家可能会想到,我们可以选择红黑树,红黑树是一颗自平衡二叉树,那这样即使是顺序插入数据,最终形成的数据结构也是一颗平衡的二叉树,结构如下:

但是,即使如此,由于红黑树也是一颗二叉树,所以也会存在一个缺点:
- 大数据量情况下,层级较深,检索速度慢。
所以,在MySQL的索引结构中,并没有选择二叉树或者红黑树,而选择的是B+Tree,那么什么是B+Tree呢?在详解B+Tree之前,先来介绍一个B-Tree。
2.3 B-Tree
在说B+Tree之前,我们先了解一下B-Tree,B-Tree又被称之为B树,而B+Tree是B-Tree的变种,B树是一种多叉路平衡查找树,相对于二叉树,B树每个节点可以有多个分支,即多叉。
以一颗最大度数(max-degree)为5(5阶)的b-tree为例,那这个B树每个节点最多存储4个key,5个指针,指针永远比key最多多1个:

知识小贴士: 树的度数指的是一个节点的子节点个数。
我们可以通过一个数据结构可视化的网站来简单演示一下。https://www.cs.usfca.edu/~galles/visualization/BTree.html

插入一组数据: 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 。然后观察一些数据插入过程中,节点的变化情况。
插入数据过程一:由于设置的为五阶,五阶最多存储4个key,5个指针,一旦节点存储的key数量到达5,就会裂变。

插入数据过程二:直接进行了裂变,中间元素向上分裂

插入数据过程三:

插入数据过程四:这时候会发现556放到了右边节点的中间位置,因为B-TREE是有序的

如下是最终结果,后面的我就不再演示了,强烈建议大家自己去网站插入看一下,这样可以更好的熟悉是数据结构!

B-Tree特点:
- 5阶的B树,每一个节点最多存储4个key,对应5个指针。
- 一旦节点存储的key数量到达5,就会裂变,中间元素向上分裂。
- 在B树中,非叶子节点和叶子节点都会存放数据。
2.4 B+Tree
B+Tree是B-Tree的变种,我们以一颗最大度数(max-degree)为4(4阶)的b+tree为例,来看一下其结构示意图:

我们可以看到,两部分:
- 绿色框框起来的部分,是索引部分,仅仅起到索引数据的作用,不存储数据。
- 红色框框起来的部分,是数据存储部分,在其叶子节点中要存储具体的数据。
我们可以通过一个数据结构可视化的网站来简单演示一下。
https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
插入一组数据: 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 。然后观察一些数据插入过程中,节点的变化情况。
如下是最终插入的结果展示:

最终我们看到,B+Tree 与 B-Tree相比,主要有以下三点区别:
所有的数据都会出现在叶子节点。叶子节点形成一个单向链表。非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。
上述我们所看到的结构是标准的B+Tree的数据结构,接下来,我们再来看看MySQL中优化之后的B+Tree。
- 所有的数据都会出现在叶子节点。
- 叶子节点形成一个单向链表。
- 非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。

mysql当中一页代表了B+TREE数据结构当中的一个叶子节点,并且一页固定大小为16kb。
总结:mysql的B+Tree数据结构,就是在原来的B+Tree结构基础上,将叶子节点的单向链表改为了双向链表
2.5 Hash
MySQL中除了支持B+Tree索引,还支持一种索引类型—Hash索引。
(1) 结构
哈希索引
