ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

05深入浅出索引(下)

2022-06-16 08:31:08  阅读:156  来源: 互联网

标签:05 深入浅出 身份证号 查询 回表 索引 NULL ID


什么是回表

初始化建表语句:

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有