【MySQL】覆盖索引和回表
- 先来了解一下两大类索引
- 聚簇索引(也称聚集索引,主键索引等)
- 普通索引(也成非聚簇索引,二级索引等)
- 聚簇索引
- 如果表设置了主键,则主键就是聚簇索引
- 如果表没有主键,则会默认第一个NOT NULL,且唯一(UNIQUE)的列作为聚簇索引
- 以上都没有,则会默认创建一个隐藏的row_id作为聚簇索引
InnoDB的聚簇索引的叶子节点存储的是行记录(其实是页结构,一个页包含多行数据),InnoDB必须要有至少一个聚簇索引。
由此可见,使用聚簇索引查询会很快,因为可以直接定位到行记录。
- 普通索引
普通索引也叫二级索引,除聚簇索引外的索引,即非聚簇索引。
InnoDB的普通索引叶子节点存储的是主键(聚簇索引)的值,而MyISAM的普通索引存储的是记录指针。
请看如下示例:
- 建表
CREATE TABLE IF NOT EXISTS `user`(
-> `id` INT UNSIGNED AUTO_INCREMENT,
-> `name` VARCHAR(),
-> `age` TINYINT(),
-> PRIMARY KEY (id),
-> INDEX idx_age (age)
-> )ENGINE=innodb charset=utf8mb4;
# id 字段是聚簇索引,age 字段是普通索引(二级索引)
- 随便加几个数据
insert into user(name,age) values('张三',);
insert into user(name,age) values('李四',);
insert into user(name,age) values('王五',);
insert into user(name,age) values('刘八',);
mysql> select * from user;
+----+------+-----+
| id | name | age |
+----+------+-----+
| | 张三 | |
| | 李四 | |
| | 王五 | |
| | 刘八 | |
+----+------+-----+
rows in set (0.06 sec)
- 索引存储结构
id 是主键,所以是聚簇索引,其叶子节点存储的是对应行记录的数据

age 是普通索引(二级索引),非聚簇索引,其叶子节点存储的是聚簇索引的的值

如果查询条件为主键(聚簇索引),则只需扫描一次B+树即可通过聚簇索引定位到要查找的行记录数据。
如:select * from user where id = ;

如果查询条件为普通索引(非聚簇索引),需要扫描两次B+树,第一次扫描通过普通索引定位到聚簇索引的值,然后第二次扫描通过聚簇索引的值定位到要查找的行记录数据。
如:select * from user where age = ;
1》先通过普通索引【age=30】定位到主键值 【id=1】

2》在通过聚集索引【id=1】定位到行记录数据

- 回表查询
先通过普通索引的值定位到聚簇索引值,在通过聚簇索引的值定位到行记录数据,要通过扫描两次索引B+树,它的性能较扫描一次较低
- 索引覆盖
只需在一颗索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。
例如:select id,age from user where age = ;
- 如何实现覆盖索引
常见的方法是:将被查询的字段,建立到联合索引里去(若查询有where条件,同时where条件字段也必须为索引字段)。
1》如实现:select id,age from user where age = 10;
explain分析:因为age是普通索引,使用到了age索引,通过一次扫描B+树即可查询到相应的结果,这样就实现了覆盖索引
此时的Extra列的【Using Index】表示进行了聚簇索引
mysql> explain select id,age from user where age = ;
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------------+
| | SIMPLE | user | NULL | ref | idx_age | idx_age | | const | | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------------+
row in set (0.07 sec)
2》如实现:select id,age,name from user where age = 10;
explain分析:age是普通索引,但name列不在索引树上,所以通过age索引在查询到id和age的值后,需要进行回表再查询name的值。
此时的Extra列的NULL表示进行了回表查询
mysql> explain select id,age,name from user where age = ;
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| | SIMPLE | user | NULL | ref | idx_age | idx_age | | const | | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
row in set (0.05 sec)
explain 使用方式如下:
EXPLAIN +SQL语句
如:EXPLAIN SELECT * FROM t1
- 为了实现索引覆盖,需要建组合索引idx_age_name(age,name)
mysql> drop index idx_age on user;
mysql> create index idx_age_name on user(`age`,`name`);
我们再次EXPLAIN分析一次:
mysql> explain select id,age,name from user where age = ;
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------------+
| | SIMPLE | user | NULL | ref | idx_age_name | idx_age_name | | const | | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------------+
row in set (0.05 sec) #可见Extra的值为【Using Index】,表示使用的覆盖索引
哪些场景适合使用索引覆盖来优化SQL:
- 全表count查询优化
mysql> explain select count(age) from user;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| | SIMPLE | user | NULL | index | NULL | idx_age_name | | NULL | | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
row in set (0.06 sec)
- 分页查询
mysql> explain select id,age,name from user order by age limit ,;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| | SIMPLE | user | NULL | index | NULL | idx_age_name | | NULL | | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
row in set (0.06 sec)
【MySQL】覆盖索引和回表的更多相关文章
- mysql覆盖索引与回表
mysql覆盖索引与回表 Harri2012关注 62019.07.28 11:14:15字数 1,292阅读 77,322 select id,name where name='shenjian' ...
- mysql:如何利用覆盖索引避免回表优化查询
说到覆盖索引之前,先要了解它的数据结构:B+树. 先建个表演示(为了简单,id按顺序建): id name 1 aa 3 kl 5 op 8 aa 10 kk 11 kl 14 jk 16 ml 17 ...
- 一篇文章讲清楚MySQL的聚簇/联合/覆盖索引、回表、索引下推
迎面走来了你的面试官,身穿格子衫,挺着啤酒肚,发际线严重后移的中年男子. 手拿泡着枸杞的保温杯,胳膊夹着MacBook,MacBook上还贴着公司标语:"加班使我快乐". 面试官: ...
- InnoDB 聚集索引和非聚集索引、覆盖索引、回表、索引下推简述
关于InnoDB 存储引擎的有聚集索引和非聚集索引,覆盖索引,回表,索引下推等概念,这些知识点比较多,也比较零碎,但是概念都是基于索引建立的,本文从索引查找数据讲述上述概念. 聚集索引和非聚集索引 在 ...
- MySQL 覆盖索引
通常大家都会根据查询的WHERE 条件来穿件合适的索引,不过这只是索引优化的一个方面.设计优秀的索引应该考虑到整个查询,而不单单是WHERE 条件部分.索引确实是一种查找数据的高效方式,但是MySQL ...
- mysql覆盖索引详解
覆盖索引的定义: 如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’.即只需扫描索引而无须回表. 只扫描索引而无需回表的优点: 1.索引条目通常远小于数据行大小,只需要读取索引, ...
- Mysql覆盖索引与延迟关联
延迟关联:通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据. 为什innodb的索引叶子节点存的是主键,而不是像myisam一样存数据的物理地址指针? 如果存的是物理地址指针不 ...
- MySQL 优化之 MRR (Multi-Range Read:二级索引合并回表)
MySQL5.6中引入了MRR,专门来优化:二级索引的范围扫描并且需要回表的情况.它的原理是,将多个需要回表的二级索引根据主键进行排序,然后一起回表,将原来的回表时进行的随机IO,转变成顺序IO.文档 ...
- mysql覆盖索引(屌的狠,提高速度)
话说有这么一个表: CREATE TABLE `user_group` ( `id` int(11) NOT NULL auto_increment, `uid` int(11) NOT NULL, ...
随机推荐
- 记一次Pinpoint监控工具部署过程
环境:Centos 7.4 X64IP:192.168.1.11 1.配置环境,先安装jdk 到Oracle官网下载安装JDK https://www.oracle.com/technetwork/j ...
- dispatch_async 的 block 中是否该使用_weak self
问题分析 我看过很多文章关于在dispatch_async的block里面使用_weak self, 但是让我疑惑的是,以下代码是否需要必须使用_weak self, 因为我也看到了很多观点说,在有些 ...
- varnish4.0缓存代理配置
防伪码:你必须非常努力,才能看起来毫不费力. 一.varnish原理: 1)Varnish简介: varnish缓存是web应用加速器,同时也作为http反向缓存代理.你可以安装varnish在任何h ...
- STL部分学习总结
一.map/multimap map/multimap映射容器的元素数据是由一个Key和一个Value成的,key与映照value之间具有一一映照的关系. map/multimap容器的数据结构也采用 ...
- FastDFS文件服务器安装指南附安装包和自启动(看此篇就够了)
安装包在最后,本文为博主自己亲自安装记录 转载请注明出处 注意文字不清晰请放大看,放大看!! 安装包地址
- 用纯css、JavaScript、jQuery简单的轮播图
完成一个可以自动切换或点击数字的轮播图 HTML代码只需要一个div 包含着一个图片和一个列表,我们主要的思路就是通过点击相应的数字,改变图片的 路径. 有4张图片都在img文件夹里,名称为 img ...
- C# 基础知识系列- 17 小工具优化
0. 前言 不知道有没有动手能力强的小伙伴照着上一篇的内容写过程序呢?如果有的话,应该会在使用的时候发现以下几个问题: 每次启动都需要经过漫长的时间去遍历磁盘里的文件目录 因为数据是用的字典保存的,所 ...
- JAVA基础篇 之 finalize()方法的作用
我们知道java有垃圾回收器负责回收无用对象占据的内存资源,但也有特殊情况:假设你的对象(并非使用new)获得了一块特殊的内存区域,由于垃圾回收器只知道回收那些经由new分配的内存,所以它不知道如 ...
- 如何快速理解Spring中的DI和AOP
前言 Spring框架通过POJO最小侵入性编程.DI.AOP.模板代码手段来简化了Java 开发,简化了企业应用的开发.POJO和模板代码相对来说好理解,本篇重点解读下DI和AOP. 一 DI DI ...
- 如何将项目发布到npm仓库
有时候,我们希望将项目里的模块提升为公共模块,以便其他项目也能使用.在前端可以将模块发布到npm仓库,这样所有项目都可以通过 npm install youProject 使用模块了. 这个过程很简单 ...