覆盖索引这回事算是整明白了

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 覆盖索引这回事算是整明白了

前言


最近公司校招,问了一个刚刚毕业的同学什么是覆盖索引,愣是没有讲明白,只知道索引是可以用来加快查询速度的。那么本文,就和大家一起分享下覆盖索引究竟是怎么一回事。


理解覆盖索引


在理解覆盖索引之前,我们先讲讲查询语句是如何利用索引进行查询的。

在MySQL的innoDB存储结构中,会有两种类型的索引:

  • 聚簇索引
  • 存放所有的数据行,它也是表数据最终存放的地方。
  • 默认在主键上建立聚簇索引,如果表没有主键,则会默认第一个NOT NULL,且唯一(UNIQUE)的列作为聚簇索引,以上都没有,则会默认创建一个隐藏的row_id作为聚簇索引。
  • 速度快,可以直接定位到具体行。
  • 普通索引
  • 结构存放聚簇索引对应的id,不会存放整个数据行。

我们用一个例子展示,比如一个学生表student, 数据如下:

id name age
1 a 18
2 b 8
3 a 16
4 b 8
5 c 5
6 e 6
  • id是主键,用来建立聚簇索引
  • nameage上建立了联合索引idx_name_age

最终得到的索引存储结构如下图所示:

1671199509958.jpg

关于索引底层数据结构不了的同学可以先阅读:一步步带你设计MySQL索引数据结构

现在我们要查询select id, name, age from student where name='a', 它的执行流程是什么样的呢?

  1. MySQL会把普通索引B+树中根目录节点所在页加载到内存中,因为是排好序了,根据'a'通过二分法快速找到它的下一层目录节点所在的页。
  2. MySQL再次把下一层目录节点所在的页加载到内存中,通过二分法找到对应的页。
  3. 最终找到叶子节点,得到的它的主键id,现在要找name, age等其他信息,就必须去另一颗聚簇索引的B+树查找。
  4. 然后根据主键id回到聚簇索引的B+树中,按照上面类似的流程再次定位到具体的行数据。这个过程也叫做 “回表”

很显然,回表的过程会在两棵树上搜索,增加了磁盘的IO, 查询性能相对会下降,那有什么办法可以只在一颗树上搜索呢?

我们看到图上的普通索引树上其实有了nameid字段的信息,如果我们查询的列只有id 和 name是不是就没有必要回到聚簇索引树上了。MySQL实际上也是这么处理的,我们可以看下查询计划就知道了。

  • 没有覆盖索引的情况

1671199517186.jpg

  • 用到了覆盖索引的情况

1671199523000.jpg

那么回到一开始的查询语句是select id, name, age from student where name='a',我们的索引树上没有age信息啊,那我们可以基于name, age建立一个联合索引就可以实现覆盖索引。

小结:

覆盖索引就是指索引树上的信息覆盖了我们要查询过滤的字段,不需要再次进行“回表”操作。所以我们在写SQL的时候尽量避免select *的情况,根据实际业务场景查询相应的字段。


优点和缺点


前面一起理解了覆盖索引,那我们辩证的看看它的优缺点。


优点


1.避免InnoDB表进行索引的二次查询(回表)

在覆盖索引中,二级索引的值中可以获取所要的数据,避免了对主键的二次查询,减少了IO操作,提升了查询效率。

2.可以把随IO变成顺序IO加快查询效率

由于覆盖索引是按值的顺序存储的,对IO密集型的范围查找来说,对比随机从磁盘读取每一行的数据IO要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的IO转变成索引查找的顺序IO。


缺点


索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。


覆盖索引使用例子


分享一个利用覆盖索引实现优化分页查询的例子。

问题:

一个常见又非常头疼的问题就是limit 3000000, 10此时需要MySQL排序前3000000记录,仅仅返回3000000~3000010的记录,查询排序的代价非常大。

1671199538904.jpg

解决方案:

SELECT * FROM student t, 
        (SELECT id FROM student ORDER BY id LIMIT 3000000,10) a 
WHERE t.id = a.id;
复制代码

1671199544921.jpg

  • 利用覆盖索引,只查找出分页范围内的id
  • 然后找出对应的id在去做连接查询。


总结


覆盖索引,其实非常容易理解,由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引也是一个常用的性能优化手段。在平时的开发过程中,我们也要尽量的使用上这个优化手段。如果本文对你有帮助的话,留下一个赞。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7月前
|
自然语言处理 关系型数据库 MySQL
一文明白MySQL索引的用法及好处
一文明白MySQL索引的用法及好处
84 0
|
PHP 开发者
很多人觉得正则表达式中的【反向引用】这个概念很难, 其实特别简单 一个案例就明白了,没你想的那么高大上!
一个案例让你明白正则表达式中的【反向引用】,其实没有你想得那么难!
103 1
很多人觉得正则表达式中的【反向引用】这个概念很难, 其实特别简单 一个案例就明白了,没你想的那么高大上!
|
缓存 自然语言处理 小程序
这个迭代写了个小程序,顺便整理了一份笔记 📒 (4000字)
这个迭代写了个小程序,顺便整理了一份笔记 📒 (4000字)
211 0
|
存储 机器学习/深度学习 算法
|
SQL 存储 关系型数据库
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(下)
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(下)
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(下)
|
存储 关系型数据库 MySQL
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(中)
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(中)
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(中)
|
存储 NoSQL 关系型数据库
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(上)
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(上)
索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!(上)
|
安全 Java
掉了两根头发,可算是把volatile整明白了
为什么只能保证可见性?又是怎么实现禁用指令重排?哇,原来这么简单
175 0
|
JavaScript
大杂烩: 踩坑记录
大杂烩: 踩坑记录
大杂烩: 踩坑记录

热门文章

最新文章