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

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 覆盖索引这回事算是整明白了

前言


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


理解覆盖索引


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

在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在去做连接查询。


总结


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

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
9月前
|
人工智能 运维 关系型数据库
|
6月前
|
存储 安全 算法
FastAdmin框架超级管理员密码重置与常规admin安全机制解析-卓伊凡|大东家
FastAdmin框架超级管理员密码重置与常规admin安全机制解析-卓伊凡|大东家
856 7
|
11月前
|
存储 缓存 NoSQL
Redis原理—4.核心原理摘要
Redis 是一个基于内存的高性能NoSQL数据库,支持分布式集群和持久化。其网络通信模型采用多路复用监听与文件事件机制,通过单线程串行化处理大量并发请求,确保高效运行。本文主要简单介绍了 Redis 的核心特性。
|
机器学习/深度学习 人工智能 算法
GitHub星标破千!斯坦福大学的284个机器学习小抄(漫画中文版)
说到人工智能必然要了解机器学习,从信息化软件,到电子商务,然后到高速发展互联网时代,到至今的云计算、大数据等,渗透到我们的生活、工作之中,在互联网的驱动下,人们更清晰的认识和使用数据,不仅仅是数据统计、分析,我们还强调数据挖掘、预测。 机器学习就是对计算机一部分数据进行学习,然后对另外一些数据进行预测与判断。 机器学习的核心是”使用算法解析数据,从中学习,然后对新数据作出决定或预测”。也就是说计算机利用已获取的数据得出某一模型,然后利用此模型进行预测的一种方法,这个过程跟人的学习过程有些类似,比如人获取一定的经验,可以对新问题进行预测。
GitHub星标破千!斯坦福大学的284个机器学习小抄(漫画中文版)
|
NoSQL Java Redis
Redis 从入门到精通之Redis Pipeline
使用Redis Pipeline可以大大提高Redis的性能和吞吐量,但需要注意命令的顺序和语义,以保证数据的正确性和一致性。同时,使用Jedis和RedisTemplate实现Redis Pipeline时,需要遵循最佳实践,避免出现错误和异常。 2. 在使用Jedis实现Redis Pipeline时,需要使用Pipeline对象添加多个命令并执行,然后通过`syncAndReturnAll`方法获取所有命令的执行结果。 3. 在使用RedisTemplate实现Redis Pipeline时,需要使用`executePipelined`方法添加多个命令并执行,然后通过返回的结果列表获取
1074 100
Redis 从入门到精通之Redis Pipeline
|
Java 应用服务中间件 Apache
Tomcat的基本使用,如何用Maven创建Web项目、开发完成部署的Web项目
Tomcat的基本使用,如何用Maven创建Web项目、开发完成部署的Web项目
354 1
|
NoSQL Redis
[Redis]——主从同步原理(全量同步、增量同步)
[Redis]——主从同步原理(全量同步、增量同步)
880 2
|
存储 缓存 编译器
Go语言解析Tag:深入探究实现原理
【2月更文挑战第20天】
890 2
|
机器学习/深度学习 JSON 自然语言处理
新一代开源语音库CoQui TTS冲到了GitHub 20.5k Star
新一代开源语音库CoQui TTS冲到了GitHub 20.5k Star
1269 0
|
存储 NoSQL 关系型数据库
图解 Redis String 底层数据结构 SDS 与计数器实战
图解 Redis String 底层数据结构 SDS 与计数器实战
831 0