05 | 深入浅出索引(下)

105 阅读3分钟

如果执行下面语句,需要执行几次树的操作,会扫描多少行?

select * from T where k between 3 and 5;

当前表的建表语句如下:

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');

image.png

看下当前这条select * from T where k between 3 and 5;的SQL语句执行流程:

  • 1.在K索引树上找到k=3的记录,取得ID=300;
  • 2.再到ID索引树查找ID=300对应的R3;
  • 3.在K索引树取下一个值 k=5,取得ID=500;
  • 4.再回到ID索引树查找ID=500对应的R4;
  • 5.在K索引树取下一个值k=6,不满足条件,循环结束。

从普通索引树回到主键索引树搜索的过程,称为回表

覆盖索引

如果执行的语句是:

select ID from T where k between 3 and 5;

此时只需要查询ID的值,而ID的值已经在k索引树上了,因此可以直接提供查询结果,无需回表。
这个查询中,索引k已经覆盖了我们的查询需求,所以称之为覆盖索引

覆盖索引可以减少数的搜索次数,显著提升查询的性能,所以是一个常用的性能优化手段。

最左前缀原则

B+ 树这种索引结构,可以利用索引的“最左前缀”,来定位记录。

用(name,age)这个联合索引来分析:

image.png

当你的逻辑需求是查到所有名字是“张三”的人时,可以快速定位到 ID4,然后向后遍历得到所有需要的结果。

如果你要查的是所有名字第一个字是“张”的人,你的 SQL 语句的条件是"where name like ‘张 %’"。这时,你也能够用上这个索引,查找到第一个符合条件的记录是 ID3,然后向后遍历,直到不满足条件为止。

索引下推

  • 作用:减少回表次数
  • 原理:可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

如果现在有一个需求:检索出表中“名字第一个字是张,而且年龄是 10 岁的所有男孩”。那么,SQL 语句是这么写的:

select * from tuser where name like '张 %' and age=10 and ismale=1;

在 MySQL 5.6 之前,只能从 ID3 开始一个个回表。到主键索引上找出数据行,再对比字段值; MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

image.png

image.png

两张图的区别是,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 10,对于不等于 10 的记录,直接判断并跳过。在我们的这个例子中,只需要对 ID4、ID5 这两条记录回表取数据判断,就只需要回表 2 次。