覆盖索引
特点:
- 覆盖索引可以很好的避免mysql的回表操作,进行性能优化
- 由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。什么是回表?
- 回表指的是 在普通索引树中找到对应的主键索引,在去主键索引树中找对应的数据,这个操作叫做回表
- 因为前面我们就已经直达 mysql 会有一个主键索引 b+tree ,创建一个普通索引就会对应生成一个 b+tree 的索引树什么是覆盖索引?
- mysql进行查询操作的时候,所要查询的字段刚好就在索引上面,查询的时候用到了该索引,那么,mysql就不用再去进行回表操作了,能直接将对应的索引字段返回
即: SQL只需要通过索引就可以返回查询所需要的数据,而不必通过二级索引查到主键之后再去查询数据。例:
- 有如下表
create table T (ID int primary key,k int NOT NULL DEFAULT 0,s varchar(16) NOT NULL DEFAULT '',index k(k))engine=InnoDB;insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

- 有如下表
执行语句
select * from T where k between 3 and 5;
- 现在,我们一起来看看这条 SQL 查询语句的执行流程:
- 在 k 索引树上找到 k=3 的记录,取得 ID = 300;
- 再到 ID 索引树查到 ID=300 对应的 R3;
- 在 k 索引树取下一个值 k=5,取得 ID=500;
- 再回到 ID 索引树查到 ID=500 对应的 R4;
- 在 k 索引树取下一个值 k=6,不满足条件,循环结束
在这个过程中,回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程读了 k 索引树的 3 条记录(步骤 1、3 和 5),回表了两次(步骤 2 和 4)。 如果执行的语句是
select ID from T where k between 3 and 5;
这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引。
最左前缀原则
一般出现在联合索引中例:
- MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引。
如User表的name和city加联合索引就是(name,city),而最左前缀原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。 如下:
select * from user where name=xx and city=xx ; //可以命中索引select * from user where name=xx ; //可以命中索引select * from user where city=xx ; //无法命中索引
like 语句也是如此,当 %在右边的时候,是有可能命中索引的,当%在左边的时候是不会命中索引的,将全表扫描.
- 我们可以根据最左前缀原则可以进行很好的管理索引,减少不必要的索引
索引下推
- 索引下推(index condition pushdown )简称ICP,在Mysql5.6的版本上推出,用于优化查询。
当where条件中的字段包含在索引中,可以在查找索引树的时候就可以进行适当的条件过滤,符合where条件的才会得到返回例子:
- 在开始之前先先准备一张用户表(user),其中主要几个字段有:id、name、age、address。建立联合索引(name,age)。
假设有一个需求,要求匹配姓名第一个为陈的所有用户,sql语句如下:
SELECT * from user where name like '陈%';
- 根据 “最佳左前缀” 的原则,这里使用了联合索引(name,age)进行了查询,性能要比全表扫描肯定要高。
问题来了,如果有其他的条件呢?假设又有一个需求,要求匹配姓名第一个字为陈,年龄为20岁的用户,此时的sql语句如下:
SELECT * from user where name like '陈%' and age=20;
这条sql语句应该如何执行呢?下面对Mysql5.6之前版本和之后版本进行分析。Mysql5.6之前的版本
- 5.6之前的版本是没有索引下推这个优化的,因此执行的过程如下图:

会忽略age这个字段,直接通过name进行查询,在(name,age)这课树上查找到了两个结果,id分别为2,1,然后拿着取到的id值一次次的回表查询,因此这个过程需要回表两次
Mysql5.6之后的版本
5.6版本添加了索引下推这个优化,执行的过程如下图:

InnoDB并没有忽略age这个字段,而是在索引内部就判断了age是否等于20,对于不等于20的记录直接跳过,因此在(name,age)这棵索引树中只匹配到了一个记录,此时拿着这个id去主键索引树中回表查询全部数据,这个过程只需要回表一次。
- 5.6之前的版本是没有索引下推这个优化的,因此执行的过程如下图:
