笔记记录自林晓斌(丁奇)老师的《MySQL实战45讲》

5) --深入浅出索引(下)

  这次的笔记从一个简单的查询开始:

  建表语句是这样的

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这条语句,需要执行几次搜索操作呢,会扫描多少行呢?由上面的建表及初始化语句我们很容易可以看出,表T上有ID字段的主键索引,也有K字段上的非主键索引。数据中满足条件K在3和5之间的记录有两条,分别是 (300,3,'cc'),(500,5,'ee')。我们在K字段上创建了索引,所以在执行这条语句时,MySQL就会使用这个索引。如果你看了我上篇笔记的话应该知道,K上的索引是非主键索引,而非主键索引存储的其实是主键的值。所以这条语句的执行流程大致是下面这个样子的。

  1. 在K索引树上找到K=3的记录,取得ID=300.
  2. 再到ID索引树查到ID=300对应的记录。(第一次回表)
  3. 在K索引树上找到K=5的记录,取得ID=500.
  4. 再到ID索引树查到ID=500对应的记录。(第二次回表)
  5. 在K索引树取下一个值K=6,不符合条件,查询结束。

所以上面这条语句查询了3条记录K=3,5,6.回表了两次。

  我们注意到一个细节,select * from T where k between 3 and 5这条语句查询的结果是*,也就是所有的字段的内容都会返回。而如果只使用K上的索引,则只能查询到ID的值与K的值,并不能返回符合要求的所有字段的值。那么如果K上的索引查询的结果可以满足要求,是不是就不需要回表了呢?答案是肯定的。 如语句 SELECT ID from T where k between 3 and 5; ID的值已经在K索引树上了,不需要回表就能返回结果。即索引“K”已经覆盖了我们的查询需求,我们称为覆盖索引。

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

  上面的例子中还有一个小细节需要注意一下在引擎内部使用索引K其实读了三个记录,但对于MySQL的Server层来说,它就是找引擎拿到了两条记录。

最左前缀原则:

  InnoDB使用B+树这种索引模型,由于B+树的索引结构,可以利用索引的"最左前缀"来定位记录。如你在‘name’字段上建立了索引,当你的语句是 where name like ‘张%’时是可以使用索引的。MySQL会利用这个索引向后遍历,直到不满足条件为止。不止是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左N个字符。索引建立联合索引的时候,如何安排索引内字段的顺序就很重要了。 有一个原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序就往往是应该优先采用的。

  如果既有联合查询,又有基于a,b各自的查询呢?如果你建立的联合索引是(a,b),那么在这种情况下,只使用b来查询是没办法使用索引的。这种时候我们需要优先考虑的就是空间了。如(name,age),name字段一般来说会比age字段占用更多的空间,那么我们建立一个(name,age)的索引再加上一个(age)的索引就好了。

索引下推:

  还是上面的(name,age)索引为例,如果你查询的条件是 姓张,且年龄小于30岁的所有男生,那么你的查询语句应该这么写。 select * from T where name like '张%'  and age = 10 and ismale = true; 由于索引前缀的规则,只能使用‘张’来找到满足条件的记录,然后再判断查询的其他条件是否满足。在MySQL5.6之前,每条满足条件 like '张%'的记录都会回表进行判断。MySQL5.6之后引入了索引下推(index condition pushdown),可以在索引遍历的过程中对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表的次数。举个例子来说明 对于记录 A(张一,40,男),B(张二,25,男),C(张三,26,女)。没有索引下推时,A,B,C都需要进行回表判断。有索引下推以后,A记录中的age值为40,age字段在查询条件中,也在索引(name,age)中,触发了索引下推,不进行回表。B,C仍需要回表。

上篇问题答案:

  对于普通索引k,重建时可以这么写:

  alter table T drop index k; alter table T add Index(k);

  对于主键索引,可以这么写:

  alter table T drop primary key; alter table T add primary key(id);

  对于上面的重建索引的作法,说出你的理解。如果有不合时的,为什么?更好的作法是什么?

  首先来回答一下为什么要重建索引? 索引可能因为记录的删除,或者页分裂等原因,导致数据页有空洞,重建索引的过程会创建一个新的索引,把数据按顺序插入,这样页面的利用率最高,也就是索引更紧凑,更省空间。

  重建索引K的做法是合理的。但重建主键过程不合理。不论是删除主键还是创建主键,都会将整个表进行重建,所以连续执行这两条语句,相当于第一个语句白做了。这两条语句可以使用 alter table T engine =InnoDB来代替。

问题:

  表结构如下所示:

CREATE TABLE `geek` (
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
`c` int(11) NOT NULL,
`d` int(11) NOT NULL,
PRIMARY KEY (`a`,`b`),
KEY `c` (`c`),
KEY `ca` (`c`,`a`),
KEY `cb` (`c`,`b`)
) ENGINE=InnoDB;

  由于历史原因, a和b需要做联合主键。那么既然主键包括了a,b这两个字段,又单独在c上创建了一个索引,索引就已经包含了三个字段了,为什么还要创建ca,cb索引呢?有人给出的理由是业务里有这样两个查询:

select * from geek where c=N order by a limit 1;
select * from geek where c=N order by b limit 1;

  这个理由对吗?为了这两个查询,这两个索引是否都必须呢?为什么呢?

MySQL 笔记整理(5) --深入浅出索引(下)的更多相关文章

  1. 最全mysql笔记整理

    mysql笔记整理 作者:python技术人 博客:https://www.cnblogs.com/lpdeboke Windows服务 -- 启动MySQL net start mysql -- 创 ...

  2. MySQL 笔记整理(4) --深入浅出索引(上)

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 4) --深入浅出索引(上) 一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样. 索引的常见模型 哈希表: ...

  3. MySQL 笔记整理(10) --MySQL为什么有时会选错索引?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 10) --MySQL为什么有时会选错索引? MySQL中的一张表上可以 ...

  4. MySQL 笔记整理(1) --基础架构,一条SQL查询语句如何执行

    最近在学习林晓斌(丁奇)老师的<MySQL实战45讲>,受益匪浅,做一些笔记整理一下,帮助学习.如果有小伙伴感兴趣的话推荐原版课程,很不错. 1) --基础架构,一条SQL查询语句如何执行 ...

  5. MySQL 笔记整理(11) --怎么给字符串字段加索引?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 11) --怎么给字符串字段加索引? 日常工作中的登录系统,你很可能会使 ...

  6. MySQL 笔记整理(9) --普通索引和唯一索引,应该怎么选择?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 9) --普通索引和唯一索引,应该怎么选择? 假如你在维护一个市民系统, ...

  7. MySQL 笔记整理(16) --“order by”是怎么工作的?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 16) --“order by”是怎么工作的? 在林老师的课程中,第15 ...

  8. MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 19) --为什么我只查一行的语句,也执行这么慢? 需要说明一下,如果M ...

  9. MySQL 笔记整理(14) --count(*)这么慢,我该怎么办?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 14) --count(*)这么慢,我该怎么办? 有时你会发现,随着系统 ...

随机推荐

  1. python中的单向链表实现

    引子 数据结构指的是是数据的组织的方式.从单个数据到一维结构(线性表),二维结构(树),三维结构(图),都是组织数据的不同方式. 为什么需要链表? 顺序表的构建需要预先知道数据大小来申请连续的存储空间 ...

  2. 10. vue axios 请求未完成时路由跳转报错问题

    axios 请求未完成时路由跳转报错问题 前两天项目基本功能算是完成了,在公司测试时遇到了遇到了一个问题,那就是在请求未完成时进行路由跳转时会报错,想了几种办法来解决,例如加loading,请求拦截, ...

  3. gc笔记(转)

    GC,即就是Java垃圾回收机制.目前主流的JVM(HotSpot)采用的是分代收集算法.与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断对象是否还存在引用.即:从gcroot开始 ...

  4. RevDebug -- VS 调试神器,你值得拥有!

    1. What's RevDebug Don't debug - replay! Trace the root cause of bugs in a matter of seconds, save y ...

  5. mantisbt的配置与安装

    下载并安装wampserver; 安装时,提示SMTP服务器时,应正确填写邮箱的SMTP的服务器地址: 安装完成后,登录phpMyAdmin; 给原有的root用户创建密码,所有root用户: 创建一 ...

  6. Java面试题:Hibernate的二级缓存与Hibernate多表查询

    我们来看两个有关Java框架之Hibernate的面试题,这是关于Hibernate的常考知识点. 1.请介绍一下Hibernate的二级缓存 解题按照以下思路来回答: (1)首先说清楚什么是缓存: ...

  7. Python程序里的注释和#号

    Python程序里的注释是很重要的.它们可以用自然语言告诉你某段代码的功能是什么.在你想要临时移除一段代码时,你还可以用注解的方式将这段代码临时禁用.接下来的练习将让你学会注释 : # A comme ...

  8. [Swift]LeetCode5. 最长回文子串 | Longest Palindromic Substring

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  9. [Swift]LeetCode877. 石子游戏 | Stone Game

    Alex and Lee play a game with piles of stones.  There are an even number of piles arranged in a row, ...

  10. 参数验证 @Validated 和 @Valid 的区别

    来源:blog.csdn.net/qq_27680317/article/details/79970590 整编:Java技术栈(公众号ID:javastack) Spring Validation验 ...