其他分享
首页 > 其他分享> > 05深入浅出索引(下)

05深入浅出索引(下)

作者:互联网

什么是回表

初始化建表语句:

mysql> 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执行流程:

  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,不满足条件,循环结束。

即:虽然读了三条记录出来,但是扫描行数是2。

在整个搜索过程中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表查询,共回表了两次。

问题:能不能优化索引,避免回表查询,提升查询性能呢?

覆盖索引(减少回表查询次数)

如果执行的语句是

select ID from T where k between 3 and 5;

这时只需要查ID的值,而ID的值已经在k索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引k已经“覆盖了”我们的查询需求,我们称为覆盖索引。

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

覆盖索引扩展

初始化市民表

CREATE TABLE `tuser` (
`id` int(11) NOT NULL,
`id_card` varchar(32) DEFAULT NULL,
`name` varchar(32) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`ismale` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_card` (`id_card`),
KEY `name_age` (`name`,`age`)
) ENGINE=InnoDB

问题:在一个市民信息表上,是否有必要将身份证号和名字建立联合索引?

我们知道,身份证号是市民的唯一标识。也就是说,如果有根据身份证号查询市民信息的需求,我们只要在身份证号字段上建立索引就够了。而再建立一个(身份证号、姓名)的联合索引,是不是浪费空间?

如果现在有一个高频请求,要根据市民的身份证号查询他的姓名,这个联合索引就有意义了。它可以在这个高频请求上用到覆盖索引,不再需要回表查整行记录,减少语句的执行时间。(特殊场景特殊处理)

最左前缀原则(排列字段顺序,缩小索引查询范围)

问题:如果为每一种查询都设计一个索引,索引是不是太多了。如果我现在要按照市民的身份证号去查他的家庭地址呢?又建立一个覆盖索引吗?

解决:

B+树这种索引结构,可以利用索引的“最左前缀”,来定位记录。(定位记录即缩小查询范围)

用(name,age)这个联合索引

由图可以看出,索引项是按照索引定义里面出现的字段顺序排序的

当你的逻辑需求是查到所有名字是“张三”的人时,可以快速定位到ID4,然后向后遍历得到所有需要的结果。不用全部扫描,缩小查询的范围。

即,在建立联合索引的时候,安排好索引内的字段顺序可以有效提高查询性能。

索引下推(过滤掉条件不满足的数据,减少回表次数)

在最左前缀索引的基础上,使用索引下推来减少回表次数,提升查询效率。

如:

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

你已经知道了前缀索引规则,所以这个语句在搜索索引树的时候,只能用 “张”,找到第一个满足条件的记录ID3。然后呢?

MySQL 5.6之前,只能从ID3开始一个个回表。到主键索引上找出数据行,再对比字段值。

MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

执行流程:

  1. 先按顺序把“name第一个字是’张’”的记录一条条取出来回表。因此,需要回表4次。

  2. 对于不等于10的记录,直接判断并跳过。在我们的这个例子中,只需要对ID4ID5这两条记录回表取数据判断,就只需要回表2次。(过滤掉第一步中不满足条件的数据,减少回表的次数)

总结

在满足语句需求的情况下, 尽量少地访问资源(如减少回表查询)是数据库设计的重要原则之一。

 

写在最后:本系列参考极客时间mysql实战45讲系列文章,只做学习笔记,原文请前往官网查看。

标签:05,深入浅出,身份证号,查询,回表,索引,NULL,ID
来源: https://www.cnblogs.com/l12138h/p/16377154.html