(MYSQL)回表查询原理,利用联合索引实现索引覆盖
一、什么是回表查询?
这先要从InnoDB的索引实现说起,InnoDB有两大类索引:
- 聚集索引(clustered index)
- 普通索引(secondary index)
InnoDB聚集索引和普通索引有什么差异?
InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引:
(1)如果表定义了PK,则PK就是聚集索引;
(2)如果表没有定义PK,则第一个not NULL unique列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;
所以PK查询非常快,直接定位行记录。
InnoDB普通索引的叶子节点存储主键值。
注意,不是存储行记录头指针,MyISAM的索引叶子节点存储记录指针。
举个栗子,不妨设有表:
t(id PK, name KEY, sex, flag);
id是聚集索引,name是普通索引。
表中有四条记录:
1, shenjian, m, A
3, zhangsan, m, A
5, lisi, m, A
9, wangwu, f, B
该聚集索引和普通索引如图:

(1)id为PK,聚集索引,叶子节点存储行记录;
(2)name为KEY,普通索引,叶子节点存储PK值,即id;
如图可知主键索引从根节点开始利用页目录通过二分法查找某个索引页,由于索引是有序的,所以在数据页中同样利用二分法查询指定记录。
普通索引和主键索引一样是棵B+树,不过普通索引的记录和页按照某个非主键列的值排序,叶子节点保存的不是完整数据,而是某个非主键列和主键,普通索引的非叶结点保存的是非主键列和页号。
(重点)一个 SQL 只能利用到复合索引中的其中一列进行范围查询,因为B+树的每个叶子节点有一个指针指向下一个节点,把某一索引列的所有的叶子节点串在了一起,只能根据单列的叶子节点进行范围查询,这就是复合索引中只能有其中一列使用索引进行范围查询的原理。
既然从普通索引无法直接定位行记录,那普通索引的查询过程是怎么样的呢?
(重点)通常情况下,需要先遍历普通索引的B+树获得聚集索引主键id,然后遍历聚集索引的B+树获得行记录的对应的值。
B+树的每个叶子节点有一个指针指向下一个节点,把所有的叶子节点串在了一起,这就是范围查询使用索引的的原理。
select * from t where name='lisi';
如下图所示流程:

如粉红色路径,需要扫码两遍索引树:
(1)先通过普通索引定位到主键值id=5;
(2)在通过聚集索引定位到行记录;
(重点)这就是所谓的回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。
二、什么是索引覆盖(Covering index)?
explain查询计划优化章节,即explain的输出结果Extra字段为Using index时,能够触发索引覆盖。
只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。
三、如何实现索引覆盖?
常见的方法是:将被查询的字段,建立到联合索引里去。
仍是《迅猛定位低效SQL》中的例子:
create table user (
id int primary key,
name varchar(20),
sex varchar(5),
index(name)
)engine=innodb;
第一个SQL语句:

select id,name from user where name='shenjian';
能够命中name索引,索引叶子节点存储了主键id,通过name的索引树即可获取id和name,无需回表,符合索引覆盖,效率较高。
Extra:Using index。
第二个SQL语句:

select id,name,sex from user where name='shenjian';
能够命中name索引,索引叶子节点存储了主键id,但sex字段必须回表查询才能获取到,不符合索引覆盖,需要再次通过id值扫描聚集索引获取sex字段,效率会降低。
Extra:Using index condition。
如果把(name)单列索引升级为联合索引(name, sex)就不同了。
create table user (
id int primary key,
name varchar(20),
sex varchar(5),
index(name, sex)
)engine=innodb;

可以看到:
select id,name ... where name='shenjian';
select id,name,sex ... where name='shenjian';
都能够命中索引覆盖,无需回表。
画外音,Extra:Using index。
四、哪些场景可以利用索引覆盖来优化SQL?
场景1:全表count查询优化

原表为:
user(PK id, name, sex);
直接:
select count(name) from user;
不能利用索引覆盖。
添加索引:
alter table user add key(name);
就能够利用索引覆盖提效。
场景2:列查询回表优化
select id,name,sex ... where name='shenjian';
这个例子不再赘述,将单列索引(name)升级为联合索引(name, sex),即可避免回表。
场景3:分页查询
select id,name,sex ... order by name limit 500,100;
将单列索引(name)升级为联合索引(name, sex),也可以避免回表。
来源:
(MYSQL)回表查询原理,利用联合索引实现索引覆盖的更多相关文章
- MySQL 回表查询 & 索引覆盖优化
回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...
- 你的 SQL 还在回表查询吗?快给它安排覆盖索引
什么是回表查询 小伙伴们可以先看这篇文章了解下什么是聚集索引和辅助索引:Are You OK?主键.聚集索引.辅助索引,简单回顾下,聚集索引的叶子节点包含完整的行数据,而非聚集索引的叶子节点存储的是每 ...
- MySQL回表查询
一.MySQL索引类型 1.普通索引:最基本的索引,没有任何限制 2.唯一索引(unique index):索引列的值必须唯一,但是允许为空 3.主键索引:特殊的唯一索引,但是不允许为空,一般在建表的 ...
- mysql多表查询原理
转:https://www.cnblogs.com/Toolo/p/3634563.html MySQL的多表查询(笛卡尔积原理) 先确定数据要用到哪些表. 将多个表先通过笛卡尔积变成一个表. 然 ...
- MySQL优化:如何避免回表查询?什么是索引覆盖? (转)
数据库表结构: create table user ( id int primary key, name varchar(20), sex varchar(5), index(name) )engin ...
- mysql中的回表查询与索引覆盖
了解一下MySQL中的回表查询与索引覆盖. 回表查询 要说回表查询,先要从InnoDB的索引实现说起.InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Sec ...
- MySql 缓存查询原理与缓存监控 和 索引监控
MySql缓存查询原理与缓存监控 And 索引监控 by:授客 QQ:1033553122 查询缓存 1.查询缓存操作原理 mysql执行查询语句之前,把查询语句同查询缓存中的语句进行比较,且是按字节 ...
- MySQL多表查询之外键、表连接、子查询、索引
MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...
- 再议 MySQL 回表
一:回表概述 关于回表的概念网上已经有很多了,这里不过多赘述.下面我们直接放一张图可能更直观说明什么是回表. 图中 非聚集索引也叫二级索引,二级索引本质上也是 一 个 B+ 树结构,与聚集索引(也叫主 ...
随机推荐
- 超级简单,把PuppyLinux安装到U盘
先说说使用感受:上网全是乱码!不支持中文 下载最新版puppylinux,从官网下载 现在U盘引导程序制作工具Unetbootin 打开下载的UNetbootin,进行下面的操作: 制作完毕后,修改U ...
- rtmp_specification_1.0
Copyright Adobe Systems Incorporated H. Parmar, Ed. M. Thornburgh, Ed. Adobe December 21, 2012 Adobe ...
- PHP Imagick文字加阴影(外发光)
PHP Imagick文字加阴影(外发光)<pre>$canvas = new \Imagick(); $canvas->newImage(500, 200, 'white'); $ ...
- [转帖]Proof Of Work 工作量证明
Proof Of Work 工作量证明 https://www.cnblogs.com/zhang-qc/p/10451817.html 借鉴了 哈希现金(Hashcash)-1997年 英国密码学专 ...
- SpringBoot配置多数据源Mysql+Sqlite
配置了一下druid的多数据源配置,尝试了很多方法,Spring boot关于对Mysql和Sqlite多数据源的配置,记录下来: 涉及技术点: Springboot + Druid + Mysq ...
- DRF框架(八)——drf-jwt手动签发与校验、搜索过滤组件、排序过滤组件、基础分页组件
自定义drf-jwt手动签发和校验 签发token源码入口 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口,不然进不了登录页面 获取提交的username ...
- Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段
单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...
- go标准库I/O模型:epoll+多协程
本文为linux环境下的总结,其他操作系统本质差别不大.本地文件I/O和网络I/O逻辑类似. epoll+多线程的模型 epoll+多线程模型和epoll 单进程区别.优点 对比于redis这 ...
- (十)pdf的构成之交叉引用表
交叉引用表(xref) 其中包含对文档中所有对象的引用.交叉引用表的目的是允许随机访问文件中的对象,因此我们不需要读取整个PDF文档来定位特定对象.每个对象由交叉引用表中的一个条目表示.(该表保存 ...
- Django使用distinct报错:DISTINCT ON fields is not supported by this database backend
具体错误提示是:django.db.utils.NotSupportedError: DISTINCT ON fields is not supported by this database back ...