一篇文章直接带你拿下 MySQL 索引

目录

索引

什么是索引?

索引有什么用?

优点

缺点

索引分类

总体

按数据结构分类

B+tree

为什么 InnoDB 选择 B+tree 当做索引?

二叉树做索引结构

红黑树做索引

B+Tree 做索引

B-Tree

B+Tree

Hash索引

按物理存储分类

按字段分类

按字段个数分类

经典思考题

思考题: 以下两条SQL语句,那个执行效率高? 为什么?

思考题: InnoDB 主键索引的 B+tree 高度为多高呢?

补充

数据结构动画展示网站:


索引

什么是索引?

索引(index)是帮助 MySQL 高效获取数据的数据结构(有序)

在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引

傻瓜都知道时间是宝贵的,当然是选择在书的目录去找,找到后再翻到对应的页。书中的目录,就是充当索引的角色,方便我们快速查找书中的内容,所以索引是以空间换时间的设计思想。

那换到数据库中,索引的定义就是帮助存储引擎快速获取数据的一种数据结构,形象的说就是索引是数据的目录

所谓的存储引擎,说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。

MySQL 存储引擎有 MyISAM 、InnoDB、Memory,其中 InnoDB 是在 MySQL 5.5 之后成为默认的存储引擎。

                                                                                        -- 文章许多内容来自小林coding

索引有什么用?

表结构及其数据如下:

假如我们要执行的SQL语句为: select * from user where age = 45;

1). 无索引情况

在无索引情况下,就需要从第一行开始扫描,一直扫描到最后一行,我们称之为全表扫描,性能很低。

需要全表扫描去查询符合的条件的记录,当数据量大的时候,全表扫描查询效率是极低的

2). 有索引情况

此时我们在进行查询时,只需要扫描三次就可以找到数据了,极大的提高的查询的效率。

注意注意!!!!!:

这里我们只是假设索引的结构是二叉树,介绍一下索引的大概原理,只是一个示意图,并不是索引的真实结构,索引的真实结构,后面会详细介绍。

特点:

优点

  1. 加速数据检索: 索引通过创建数据的有序结构,允许数据库快速定位和提取数据,尤其是处理大量数据时,索引可以显著缩短查询时间
  2. 提高查询效率覆盖索引可以避免全表扫描,直接从索引中获取所需数据,减少 I/O操作
  3. 支持排序和唯一性: B-Tree 索引自然地支持数据排序,可以加速 ORDER BY 操作。唯一性索引可以确保数据的唯一性,防止重复数据的插入。
  4. 促进数据完整性唯一索引和主键索引可以帮助维护数据的完整性和一致性,确保数据库的可靠性和准确性。
  5. 空间索引和全文索引: 特殊类型的索引,如空间索引和全文索引,可以支持复杂的数据查询,如地理空间数据查询和文本搜索。

缺点

  1. 增加写操作成本: 插入、更新和删除操作需要额外的时间来维护索引树的结构,这可能会降低写操作的性能。特别是在高并发写入场景下,索引的维护开销更加明显。
  2. 占用存储空间: 索引本身需要存储空间,尤其是当数据量大时,索引可能会占用相当大的磁盘空间。
  3. 查询优化问题: 如果索引设计不当,或者查询语句构造不佳,数据库优化器可能无法有效地利用索引,导致性能下降。
  4. 维护和管理成本: 需要定期分析和优化索引,以保持其高效运行。此外,索引的创建和删除操作也可能消耗资源。
  5. 锁竞争: 在高并发环境中,尤其是在使用行级锁的存储引擎(如InnoDB)中,索引上的频繁读写操作可能导致锁竞争,进而影响性能。
  6. 数据倾斜:对于那些具有大量重复值的列,索引的效果可能不明显,因为索引的数据结构可能变得非常宽,从而降低了其效率。

索引分类

总体

  • 按「数据结构」分类:B+tree索引、Hash索引、Full-text索引、R-tree索引
  • 按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)
  • 按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引
  • 按「字段个数」分类:单列索引、联合索引

在创建表时,InnoDB 存储引擎会根据不同的场景选择不同的列作为索引:

  • 如果有主键,默认会使用主键作为聚簇索引的索引键(key);
  • 如果没有主键,就选择第一个不包含 NULL 值的唯一列作为聚簇索引的索引键(key);
  • 在上面两个都没有的情况下,InnoDB 将自动生成一个隐式自增 id 列作为聚簇索引的索引键(key);

其它索引都属于辅助索引(Secondary Index),也被称为二级索引或非聚簇索引。

创建的主键索引和二级索引默认使用的是 B+Tree 索引

按数据结构分类

主要介绍 B+Tree索引和 Hash索引

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

注:

虽然 InnoDB 不支持Hash索引,但是在内存结构中有一个自适应 Hash索引!!!!

B+tree
为什么 InnoDB 选择 B+tree 当做索引?

那我们下面就讲讲为啥选择!!!!!!!

二叉树做索引结构

最好的情况 是一颗 满二叉搜索树

时间复杂度 O(log n) 查询效率确实大大提升

但是最坏的情况 当我们按照 顺序插入 从 36 34 33 。。。。 到 17

那就形成一个单向链表

复杂度变为O(n) 查询效率是极低的

所以,如果选择二叉树作为索引结构,会存在以下缺点:

  • 顺序插入时,会形成一个链表,查询性能大大降低。
  • 大数据量情况下,层级较深,检索速度慢。
红黑树做索引

此时大家可能会想到,我们可以选择红黑树,红黑树是一颗自平衡二叉树,那这样即使是顺序插入数据,最终形成的数据结构也是一颗平衡的二叉树,结构如下:

使用红黑树确实解决了二叉树退化为链表的问题,但是,即使如此,由于红黑树也是一颗二叉树,所以也会存在一个缺点:

        大数据量情况下,层级较深,检索速度慢。

B+Tree 做索引

在MySQL的索引结构中,并没有选择二叉树或者红黑树,而选择的是B+Tree,那么什么是 B+Tree呢?

在详解B+Tree之前,先来介绍一个B-Tree。

B-Tree

B-Tree,B树是一种多叉路衡查找树,相对于二叉树,B树每个节点可以有多个分支,即多叉。 以一颗最大度数(max-degree)为5(5阶)的 b-tree 为例,那这个B树每个节点最多存储4个key5 个指针

数据结构可视化网站:点我进入 !!!!!

特点:

  • 5阶的B树,每一个节点最多存储4个key,对应5个指针
  • 一旦节点存储的 key 数量到达5,就会裂变中间元素向上分裂(具体过程可以使用数据结构可视化网站了解)
  • 在B树中,非叶子节点和叶子节点都会存放数据。

主角总是最后登场 来喽 , 来喽!!!!!!!!!!!

B+Tree

B+Tree 是 B-Tree 的变种,我们以一颗最大度数(max-degree)为4(4阶)的B+tree为例,来看一 下其结构示意图:

  • 绿色框框起来的部分,是索引部分,仅仅起到索引数据的作用,不存储数据
  • 红色框框起来的部分,是数据存储部分,在其叶子节点中要存储具体的数据

可视化网站图:

插入一组数据: 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 进行了优化

在原 B+Tree 的基础上,增加一个指向相邻叶子节点 的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,利于排序

Hash索引

MySQL中除了支持B+Tree索引,还支持一种索引类型---Hash索引。

结构 哈希索引就是采用一定的hash算法,将键值换算成新的 hash 值,映射到对应的槽位上,然后存储在 hash表中。

如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了 hash冲突(也称为 hash碰撞),可 以通过链表来解决。

特点

  • Hash 索引只能用于等值查询(=,in),不支持范围查询(between,>,< ,...)
  • 无法利用索引完成排序操作
  • 查询效率高,通常(不存在hash冲突的情况)只需要一次检索就可以了,效率通常要高于 B+tree 索引

按物理存储分类

而在在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:

分类

含义

特点

聚集索引(Clustered Index)

将数据存储于索引放到了一块,索引结构的叶子节点保存了行数据

必须有,而且只有一个

二级索引(Secondary Index)

将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键

可以存在多个

聚集索引选取规则:

  • 如果存在主键,主键索引就是聚集索引。
  • 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
  • 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。

聚集索引和二级索引的具体结构如下:

  • 聚集索引的叶子节点下挂的是这一行的数据
  • 二级索引的叶子节点下挂的是该字段值对应的主键值

接下来,我们来分析一下,当我们执行如下的SQL语句时,具体的查找过程是什么样子的。

具体过程如下:

  • 由于是根据name字段进行查询,所以先根据 name='Arm' 到 name 字段的二级索引中进行匹配查找。但是在二级索引中只能查找到 Arm 对应的主键值 10。
  • 由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的行 row。
  • 最终拿到这一行的数据,直接返回即可。

回表查询:

所以,在查询时使用了二级索引,如果查询的数据能在二级索引里查询的到,那么就不需要回表,这个过程就是覆盖索引

如果查询的数据不在二级索引里,就会先检索二级索引,找到对应的叶子节点,获取到主键值后,然后再检索主键索引,就能查询到数据了,这个过程就是回表

回表查询会影响查询的性能,因为回表不仅仅是多查一次。还会带来随机IO(不了解随机IO的可以看看这个文章:顺序IO 和 随机IO-CSDN博客

因为通过 id 去主键索引查询的时候,id肯定是不连续的,所以主键索引频繁查询会造成大量随机IO,我们都知道顺序 I/O 查询快,所以频繁回表效率很低。

按字段分类

按字段个数分类

从字段个数的角度来看,索引分为单列索引、联合索引(复合索引)。

  • 建立在单列上的索引称为单列索引,比如主键索引
  • 建立在多列上的索引称为联合索引;
CREATE INDEX index_product_no_name ON product(product_no, name);

注:

联合索引的知识也涉及到很多,比如最左匹配原则,啥时候会失效啥的,后续也会专门写一篇文章!!!


经典思考题

思考题: 以下两条SQL语句,那个执行效率高? 为什么?

  • A. select * from user where id = 10 ;
  • B. select * from user where name = 'Arm' ;
    • 备注: id 为主键,name字段创建的有索引

解答:

A 语句的执行性能要高于 B 语句。因为 A语句直接走聚集索引直接返回数据

B语句需要先查询name字段的二级索引,然 后再查询聚集索引,也就是需要进行回表查询。

思考题: InnoDB 主键索引的 B+tree 高度为多高呢?

假设: 一行数据大小为1k,一页中可以存储16行这样的数据。

InnoDB 的指针占用 6个字节的空 间,主键即使为 bigint,占用字节数为 8。

高度为2:

n * 8 + (n + 1) * 6 = 16*1024 , 算出 n 约为 1170

1171* 16 = 18736

也就是说,如果树的高度为2,则可以存储 18000 多条记录。

解析:

高度为3:

1171 * 1171 * 16 = 21939856

也就是说,如果树的高度为3,则可以存储 2200w 左右的记录。

这也是为什么InnoDB 选择 B+Tree树做索引的一个原因,即使数据量很大,但是树仍然不是很高(矮胖型),MySQL去磁盘IO的次数就少了,大大提高了查询的性能。

思考题: 为什么 MySQL InnoDB 选择 B+tree 作为索引的数据结构?

1、B+Tree vs B Tree

B+Tree 只在叶子节点存储数据,而 B 树 的非叶子节点也要存储数据,所以 B+Tree 的单个节点的数据量更小,在相同的磁盘 I/O 次数下,就能查询更多的节点。

另外,B+Tree 叶子节点采用的是双链表连接,适合 MySQL 中常见的基于范围的顺序查找,而 B 树无法做到这一点。

2、B+Tree vs 二叉树

对于有 N 个叶子节点的 B+Tree,其搜索复杂度为O(logdN),其中 d 表示节点允许的最大子节点个数为 d 个。

在实际的应用当中, d 值是大于100的,这样就保证了,即使数据达到千万级别时,B+Tree 的高度依然维持在 3~4 层左右,也就是说一次数据查询操作只需要做 3~4 次的磁盘 I/O 操作就能查询到目标数据。

而二叉树的每个父节点的儿子节点个数只能是 2 个,意味着其搜索复杂度为 O(logN),这已经比 B+Tree 高出不少,因此二叉树检索到目标数据所经历的磁盘 I/O 次数要更多。

3、B+Tree vs Hash

Hash 在做等值查询的时候效率贼快,搜索复杂度为 O(1)。

但是 Hash 表不适合做范围查询,它更适合做等值的查询,这也是 B+Tree 索引要比 Hash 表索引有着更广泛的适用场景的原因。

                                                                                                   ---内容来自小林coding


补充

数据结构动画展示网站:

为了更好的理解一些数据结构,推荐个数据结构动画展示网站点我进入 !!!!!

使用网页翻页软件翻译一下啦

 看到这觉得文章还可以的,给个小赞哦!!!谢谢

爽文推荐 干货满满:

了解 MySQL体系结构 和 存储引擎 这一篇文章就够了-CSDN博客

  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值