你的 SQL 还在回表查询吗?快给它安排覆盖索引
什么是回表查询
小伙伴们可以先看这篇文章了解下什么是聚集索引和辅助索引:Are You OK?主键、聚集索引、辅助索引,简单回顾下,聚集索引的叶子节点包含完整的行数据,而非聚集索引的叶子节点存储的是每行数据的辅助索引键 + 该行数据对应的聚集索引键(主键值)。
假设有张 user 表,包含 id(主键),name,age(普通索引)三列,有如下数据:
id name age
1 Jack 18
7 Alice 28
10 Bob 38
20 Carry 48
画一个比较简单比较容易懂的图来看下聚集索引和辅助索引:
聚集索引:

辅助索引(age):

如果查询条件为主键,则只需扫描一次聚集索引的 B+ 树即可定位到要查找的行记录。举个例子:
select * from user where id = 7;
查找过程如图中绿色所示:

如果查询条件为普通索引(辅助索引) age,则需要先查一遍辅助索引 B+ 树,根据辅助索引键得到对应的聚集索引键,然后再去聚集索引 B+ 树中查找到对应的行记录。举个例子:
select * from user where age = 28;
上述 select * 等同于 select id, age, name 对吧,id 是主键索引,age 是普通索引,而 name 并不存在于 age 索引的 B+ 树上,所以通过 age 索引查询到 id 和 age 的值之后,还需要去聚集索引上才能查到 name 的值。
如图所示,第一步,查 age 辅助索引:

第二步,查聚集索引:

这就是所谓的回表查询,因为需要扫描两次索引 B+ 树,所以很显然它的性能较扫一遍索引树更低。
什么是覆盖索引
覆盖索引的目的就是避免发生回表查询,也就是说,通过覆盖索引,只需要扫描一次 B+ 树即可获得所需的行记录。
如何实现覆盖索引
上文解释过,下面这个 SQL 语句需要查询两次 B+ 树:
select * from user where age = 28;
我们将其稍作修改,使其只需要查询一次 B+ 树:
select id, age from user where age = 28;
之前我们的返回结果是整个行记录,现在我们的返回结果只需要 id 和 age。
id 是什么?主键索引(聚集索引),age 是什么?普通索引(辅助索引),age 索引的 B+ 树的叶子节点存储的是什么?辅助索引键 + 对应的聚集索引键
所以这条 SQL 语句只需要扫描一次 age 索引的 B+ 树就行了

这样,结合这个例子,不知道各位有没有受到启发,如何实现覆盖索引拒绝回表查询呢?
答:联合索引。
我们把 age,name 设置为联合索引:
create index idx_age_name on user(`age`,`name`);
此时 age 和 name 作为辅助索引键都在同一棵辅助索引的 B+ 树上,所以只需扫描一次这个组合索引的 B+ 树即可获取到 id、age 和 name,这就是实现了索引覆盖
覆盖索引的常见使用场景
在下面三个场景中,可以使用覆盖索引来进行优化 SQL 语句:
1)列查询回表优化(如上面讲的例子,将单列索引 age 升级为联合索引(age, name))
2)全表 count 查询
举个例子,假设 user 表中现在只有一个索引即主键 id:
select count(age) from user;
可以用 explain 分析下这条语句,如果 Extra 字段为 Using index 时,就表示触发索引覆盖:

显然现在是没有触发覆盖索引的,我们来优化下:将 age 列设置为索引 create index idx_age on user(age),这样只需要查一遍 age 索引的 B+ 树即可得到结果:

3)分页查询
select id, age, name from user order by username limit 500, 100;
对于这条 SQL,因为 name 字段不是索引,所以在分页查询需要进行回表查询。

Using filesort 表示没有使用索引的排序,或者说表示在索引之外,需要额外进行外部的排序动作。看到这个字段就应该意识到你需要对这条 SQL 进行优化了。
使用索引覆盖优化:将 (age, name) 设置为联合索引,这样只需要查一遍 (age, name) 联合索引的 B+ 树即可得到结果。

我是小牛肉,长风破浪会有时,小伙伴们下篇文章再见
关注公众号 | 飞天小牛肉,即时获取更新
博主东南大学硕士在读,携程 Java 后台开发暑期实习生,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 技术栈等相关原创技术好文。本公众号的目的就是让大家可以快速掌握重点知识,有的放矢。关注公众号第一时间获取文章更新,成长的路上我们一起进步
并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.8k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~
如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 900+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中。
你的 SQL 还在回表查询吗?快给它安排覆盖索引的更多相关文章
- mysql中的回表查询与索引覆盖
了解一下MySQL中的回表查询与索引覆盖. 回表查询 要说回表查询,先要从InnoDB的索引实现说起.InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Sec ...
- (MYSQL)回表查询原理,利用联合索引实现索引覆盖
一.什么是回表查询? 这先要从InnoDB的索引实现说起,InnoDB有两大类索引: 聚集索引(clustered index) 普通索引(secondary index) InnoDB聚集索引和普通 ...
- MySQL优化:如何避免回表查询?什么是索引覆盖? (转)
数据库表结构: create table user ( id int primary key, name varchar(20), sex varchar(5), index(name) )engin ...
- MySQL 回表查询 & 索引覆盖优化
回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...
- MySQL回表查询
一.MySQL索引类型 1.普通索引:最基本的索引,没有任何限制 2.唯一索引(unique index):索引列的值必须唯一,但是允许为空 3.主键索引:特殊的唯一索引,但是不允许为空,一般在建表的 ...
- Oracle总结【SQL细节、多表查询、分组查询、分页】
前言 在之前已经大概了解过Mysql数据库和学过相关的Oracle知识点,但是太久没用过Oracle了,就基本忘了...印象中就只有基本的SQL语句和相关一些概念....写下本博文的原因就是记载着Or ...
- 2.2 Oracle之DML的SQL语句之多表查询以及组函数
一.SQL的多表查询: 1.左连接和右连接(不重要一方加(+)) SELECT e.empno,e.ename,d.deptno,d.dname,d.loc FROM emp e,dept d WHE ...
- SQL数据库的多表查询
多表查询分为 内.外连接 外连接分为左连接(left join 或left outer join).右连接(right join 或者 right outer join).和完整外部连接 (full ...
- SQL语句 自连表查询。inner join用法,partition by ,列转行查询
use mydb1 go -- 表T_Employee2 -- Id Name Position Dept -- 1 张三 员工 市场部 -- 2 李四 经理 销售部 -- 3 王五 经理 市场部 - ...
随机推荐
- 17Java进阶——反射、进程、Java11新特性
1.Java反射机制 Java反射(Reflection)概念:在运行时动态获取类的信息以及动态调用对象方法的功能. 1.1反射的应用--通过全类名获取类对象及其方法 package two.refl ...
- phpmyadmin scripts/setup.php 反序列化漏洞(WooYun-2016-199433)
phpmyadmin 2.x版本 POST /scripts/setup.php HTTP/1.1 Host: 192.168.49.2:8080 Accept-Encoding: gzip, def ...
- 网安日记③之通过iis搭建ftp并使用通过serv-u搭建ftp
通过iis搭建ftp并使用通过serv-u搭建ftp 安装iis的ftp访问 由于在安装iis时勾选了ftp服务,我们直接在iis界面右键ftp服务打开属性查看本地路径 在电脑目录下打开安装目录,并在 ...
- SpringBoot+Maven 多模块项目的构建、运行、打包实战
前言 最近在做一个很复杂的会员综合线下线上商城大型项目,单模块项目无法满足多人开发和架构,很多模块都是重复的就想到了把模块提出来,做成公共模块,基于maven的多模块项目,也好分工开发,也便于后期微服 ...
- Java 日志框架概述(slf4j / log4j / JUL / Common-logging(JCL) / logback)
一.简介 JAVA日志在初期可能官方并没有提供很好且实用的规范,导致各公司或OSS作者选择自行造轮子,这也导致了目前初学者觉得市面上 Java 日志库繁杂的局面. 现在市面流行以 slf4j(Simp ...
- 腾讯技术团队整理,为什么 Flutter 能最好地改变移动开发
导语 | Flutter 框架是当下非常热门的跨端解决方案,能够帮助开发者通过一套代码库高效构建多平台精美应用,支持移动.Web.桌面等多端开发.但仍然有很多产品.设计.甚至开发同学并不了解 Flut ...
- docker容器存储
写在前面 我们在上篇学习了容器网络,对容器网络驱动bridge工作原理做了较为详细的介绍,今天小作文一起看看容器中另一个关键域-存储. 容器的存储可以分为两大类: 一种是与镜像相关的即我们在<d ...
- 七夕特别篇|用Python绘画牛郎织女在鹊桥相见
大家好,我是辰哥~ 今天就是七夕节,首先提前祝福有伴侣的小伙伴,七夕快乐,没有伴侣的小伙伴,今天就会找到伴侣,(给看到这句话的你好运加持,哈哈哈). 作为会Python的我们必须做点好玩且有意义的东西 ...
- Golang语言系列-11-goroutine并发
goroutine 并发 概念 package main import ( "fmt" "time" ) /* [Go语言中的并发编程 goroutine] [ ...
- Java 多线程与并发【原理第二部分笔记】
Java 多线程与并发[原理第二部分笔记] 什么是Java内存模型中的happens-before Java内存模型,即JMM,本身是一种抽象的概念,并不是真实存在的,他描述的是一组规则或者说是一种规 ...