一、什么是回表查询?

这先要从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),也可以避免回表。

来源:

https://www.toutiao.com/a6730525445139202571/?timestamp=1567214250&app=news_article&group_id=6730525445139202571&req_id=201908310917300100230391636384A3E

(MYSQL)回表查询原理,利用联合索引实现索引覆盖的更多相关文章

  1. MySQL 回表查询 & 索引覆盖优化

    回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...

  2. 你的 SQL 还在回表查询吗?快给它安排覆盖索引

    什么是回表查询 小伙伴们可以先看这篇文章了解下什么是聚集索引和辅助索引:Are You OK?主键.聚集索引.辅助索引,简单回顾下,聚集索引的叶子节点包含完整的行数据,而非聚集索引的叶子节点存储的是每 ...

  3. MySQL回表查询

    一.MySQL索引类型 1.普通索引:最基本的索引,没有任何限制 2.唯一索引(unique index):索引列的值必须唯一,但是允许为空 3.主键索引:特殊的唯一索引,但是不允许为空,一般在建表的 ...

  4. mysql多表查询原理

    转:https://www.cnblogs.com/Toolo/p/3634563.html MySQL的多表查询(笛卡尔积原理)   先确定数据要用到哪些表. 将多个表先通过笛卡尔积变成一个表. 然 ...

  5. MySQL优化:如何避免回表查询?什么是索引覆盖? (转)

    数据库表结构: create table user ( id int primary key, name varchar(20), sex varchar(5), index(name) )engin ...

  6. mysql中的回表查询与索引覆盖

    了解一下MySQL中的回表查询与索引覆盖. 回表查询 要说回表查询,先要从InnoDB的索引实现说起.InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Sec ...

  7. MySql 缓存查询原理与缓存监控 和 索引监控

    MySql缓存查询原理与缓存监控 And 索引监控 by:授客 QQ:1033553122 查询缓存 1.查询缓存操作原理 mysql执行查询语句之前,把查询语句同查询缓存中的语句进行比较,且是按字节 ...

  8. MySQL多表查询之外键、表连接、子查询、索引

    MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...

  9. 再议 MySQL 回表

    一:回表概述 关于回表的概念网上已经有很多了,这里不过多赘述.下面我们直接放一张图可能更直观说明什么是回表. 图中 非聚集索引也叫二级索引,二级索引本质上也是 一 个 B+ 树结构,与聚集索引(也叫主 ...

随机推荐

  1. 移芯EC616修改记录

    1. FOTA升级的不用修改了,发布的版本已经修改过. 2. 添加AT+LPNM和AT+LGMR

  2. nodejs调试工具 node-inspect

    1.安装 npm install -g node-inspect 2.chrome设置 chrome://flags/#enable-devtools-experiments 3.测试 测试代码mai ...

  3. JS系列:三元运算符与循环

     三元运算符 语法: 条件?成立做的事情:不成立做的事情:<=>相当于简单的if/else判断(简化写法) var num = 12; if(num>10){ num ++; }el ...

  4. c++中共享内存原理及实现

    共享内存 (也叫内存映射文件) 主要是通过映射机制实现的 , Windows 下进程的地址空间在逻辑上是相互隔离的 , 但在物理上却是重叠的 ; 所谓的重叠是指同一块内存区域可能被多个进程同时使用 , ...

  5. 解决GitHub下载慢或下载失败问题

    1.登录自己的码云账户 码云网站:https://gitee.com/luckyplj8/events 2.新建一个仓库. 3.选择导入已有仓库. GitHub资源链接: 4.等待码云克隆项目,大概1 ...

  6. java.lang.IllegalArgumentException,java.util.zip.ZipException 解决办法

    控制台错误信息: 严重: A child container failed during start java.util.concurrent.ExecutionException: org.apac ...

  7. [转帖]Flink(一)Flink的入门简介

    Flink(一)Flink的入门简介 https://www.cnblogs.com/frankdeng/p/9400622.html 一. Flink的引入 这几年大数据的飞速发展,出现了很多热门的 ...

  8. 【VUE】1.搭建一个webpack项目

    1.npm之类的安装跳过 2.安装npm install -g @vue/cli-init 初始化项目目录 vue init webpack vue_cutter_point_blog_admin 并 ...

  9. Kibana访问报错

    浏览器访问提示:Kibana server is not ready yet 查看日志如下 {"type":"log","@timestamp&quo ...

  10. NETRemoting学习笔记

    1..NET Remoting概念 1.一种分布式处理方式.从字面意义上看出,他是基于.net平台的一种远程对象开发技术,该技术是将远程计算机中的数据视为分布式对象来进行开发. 2.一种网络通信技术. ...