美文网首页
五、深入浅出索引(下)

五、深入浅出索引(下)

作者: nieniemin | 来源:发表于2021-05-06 19:08 被阅读0次

在下面这个表T中,执行 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'),(700,7,'gg');
InnoDB的索引组织结构

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

在这个过程中,回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程读了k索引树的3条记录(步骤1、3和5),回表了两次(步骤2和4)。

5.1 覆盖索引

如果执行的语句是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</pre>

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

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

当然,索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这正是业务DBA,或者称为业务数据架构师的工作。

5.2 最左前缀原则

在mysql中执行查询时,只能使用一个索引。下面的查询sql语句中,假设我们现在只在name上建索引,可以快速把范围限制在一个结果集A,然后在A中扫描符合条件的age。这样扫描出来的结果集仍然远远大于我们的实际需要。为了提高搜索效率,我们需要考虑运用多列索引,即联合索引。

 select id from tuser where   name=? and age=? 

最左前缀:顾名思义,就是最左优先,上例中我们创建了name,ages多列索引,相当于创建了(name)单列索引,(name,age)组合索引。

5.3 索引下推

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

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

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

无索引下推执行流程 索引下推执行流程

上图中每一个虚线箭头表示回表一次。

无索引下推执行流程在(name,age)索引里面我特意去掉了age的值,这个过程InnoDB并不会去看age的值,只是按顺序把“name第一个字是’张’”的记录一条条取出来回表。因此,需要回表4次。

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

总结:
1、回表:SQL查询过程中,需要回到主键索引树搜索的过程,我们称为回表。
2、覆盖索引:如果查询条件使用的是普通索引(或是联合索引的最左原则字段),查询结果是联合索引的字段或是主键,不用回表操作,直接返回结果,减少IO磁盘读写读取正行数据
3、最左前缀:最左优先,以最左边的为起点任何连续的索引都能匹配上
4、联合索引:根据创建联合索引的顺序,以最左原则进行where检索,比如(age,name)以age=1 或 age= 1 and name=‘张三’可以使用索引,单以name=‘张三’ 不会使用索引,考虑到存储空间的问题,还请根据业务需求,将查找频繁的数据进行靠左创建索引。
5、索引下推:like 'hello%’and age >10 检索,MySQL5.6版本之前,会对匹配的数据进行回表查询。5.6版本后,会先过滤掉age<10的数据,再进行回表查询,减少回表率,提升检索速度

相关文章

  • 五、深入浅出索引(下)

    在下面这个表T中,执行 select * from T where k between 3 and 5,需要执行几...

  • 05 | 深入浅出索引(下)

    知识点 1 覆盖索引是常用的优化手段2 引擎层覆盖索引实际扫描行数可能和 server 层显示不一样3 案例 : ...

  • 05 | 深入浅出索引(下)

    感谢极客时间:https://time.geekbang.org/column/article/69636

  • MySQL深入浅出索引(下)

    在上一篇文章中,我和你介绍了 InnoDB 索引的数据结构模型,今天我们再继续聊聊跟 MySQL 索引有关的概念。...

  • 05 | 深入浅出索引(下)

    在开始这篇文章之前,我们先来看一下这个问题:在下面这个表 T 中,如果我执行 select * from T wh...

  • 04 | 讲深入浅出索引(上)

    04 | 讲深入浅出索引(上)索引结构 : 哈希表 , 有序数组 , 查找树 (都是查找表)哈希只能 equa...

  • 【MySQL】5|深入浅出索引(下)

    上一篇介绍了InnoDB索引的数据结构模型,这一篇将继续介绍MySQL索引有关的概念。 在开始之前,先看一下这个问...

  • SQL索引的作用(转载)

    深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索引:聚集索引...

  • Mysql学习(五)索引 下

    学习笔记 InnoDB会把主键字段放到索引定义字段后面 在下面这个表 T 中,如果我执行 select * fro...

  • 深入浅出索引

    数据库培训后的总结 数据结构 上图中分别出现了BST、AVL、B-Tree、B+Tree,其中BST和AVL都很熟...

网友评论

      本文标题:五、深入浅出索引(下)

      本文链接:https://www.haomeiwen.com/subject/jxwddltx.html