此博客的内容主要来源于尚硅谷的视频中,在此记录,以备以后自己查看。

准备

创建staff表:

DROP TABLE IF EXISTS `staffs`;
CREATE TABLE `staffs`(
  id INT PRIMARY KEY AUTO_INCREMENT,
  staname VARCHAR (24)  NULL DEFAULT '' COMMENT '姓名',
  age INT NOT NULL DEFAULT 0 COMMENT '年龄',
  email varchar(20) NULL DEFAULT '' COMMENT '邮箱',
  pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '职位',
  add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间'
) CHARSET utf8 COMMENT '员工记录表' ;

INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES('z3',22,'manager',NOW());
INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES('July',23,'dev',NOW());
INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES('2000',23,'dev',NOW());
INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES(null,23,'dev',NOW());
SELECT * FROM staffs;

MySQL高级知识(七)——索引优化准则

规则:

1. 最佳左前缀原则

1.1. 定义:

  • 在创建了多列索引的情况下,查询从索引的最左前端列开始且不能跳过索引中的列
  • 最佳左前缀法则就是说,如果我们创建了多个索引,在使用索引的时候要按照创建索引的顺序来使用,中间不能缺少或者跳过,当然如果知识使用了最左边的索引列,也就是第一个索引是可以的。
  • 俗话理解就是"带头大哥不能死,中间兄弟不能断"

1.2. 事例

  • 事例1

创建组合索引,并执行explain
MySQL高级知识(七)——索引优化准则
分析:

  1. 索引的创建顺序是staname,age,pos;
  2. 直接使用staname(带头大哥)作为条件,可以看到type=ref,key_len=75,ref=const,效果不错

  • 事例2

MySQL高级知识(七)——索引优化准则
分析:

没使用带头大哥(staname),直接使用兄弟,type=ALL,为全表扫描。


  • 事例3

MySQL高级知识(七)——索引优化准则
分析:
使用了带头大哥(staname),之后使用了age,所以type=ref,ref=const,const。

注意:
and 忽略左右关系。就是我们即使没有按照顺序,但是mysql由于优化器的存在,会自动优化这个。


  • 事例4

MySQL高级知识(七)——索引优化准则
MySQL高级知识(七)——索引优化准则
分析:

  1. 对比上面两个sql语句可发现:火车头(staname)和中间车厢(age)、火车头(staname)和车尾(pos)。

  2. 虽然type=ref,但是观察key_len和ref两项,并对比Case1中的结果,可得出在使用火车头(name)和车尾(gender)时,只使用了部分索引也就是火车头(name)的索引。

  3. 通俗理解:火车头单独跑没问题,火车头与直接相连的车厢一起跑也没问题,但是火车头与车尾,如果中间没有车厢,只能火车头自己跑。


  • 事例5

MySQL高级知识(七)——索引优化准则
分析:
火车头 + 车厢 + 车尾,三者串联,就变成了整个火车。type=ref,key_len=141,ref=const,const,const。此处的and左右顺序关系可以忽略,mysql优化器会自动优化。

1.3. 总结

带头大哥不能死,中间兄弟不能断;带头大哥可跑路,老二也可跟着跑,其余兄弟只能死。

2. 不要在索引列上面做任何的操作

在索引列上面做任何的操作(计算、函数、(自动or手动)类型转换),会导致索引失效从而转向全表扫描。

  • 事例1

MySQL高级知识(七)——索引优化准则
分析:

  • 这里使用了函数计算,type=ALL,导致索引失效。

  • 事例2

MySQL高级知识(七)——索引优化准则


分析:

  • 将name=‘Tom’的值修改为‘123’,使用sql后,发生了类型转换,type=ALL,导致全表扫描。

  • 如果条件为where staname = ‘123’,那么没有发生类型转换。


在索引列上做任何操作,都会导致索引失效转向全表扫描。

3. 范围右边全失效

存储引擎不能使用索引中范围右边的列,也就是说范围右边的索引列会失效。

  • 事例1

MySQL高级知识(七)——索引优化准则


  • 事物2

MySQL高级知识(七)——索引优化准则


  • 事物3

MySQL高级知识(七)——索引优化准则


  • 事物4

MySQL高级知识(七)——索引优化准则


  • 对比:
    • 条件单独使用name时候,type=ref,key_len=75,ref=const。

    • 条件加上age时(使用常量等值),type=ref,key_len=79,ref=const,const。

    • 当全值匹配时,type=ref,key_len=141,ref=const,const,const。说明索引全部用上,从key_len和ref可以看出。(and忽略左右)

    • 当使用范围时(age>22),type=79,key_len=79,ref=Null,与事例1、事例2和事例3可以,使用了部分索引,但是pos这个字段的索引并没有使用上。


范围右边的索引列失效。

4. 尽量使用覆盖索引

尽量使用覆盖索引(查询列和索引列尽量保持一直,通俗的讲就是对A、B列创建了索引,然后查询中尽量也使用A、B列),减少select * 的使用。

  • 事例1

MySQL高级知识(七)——索引优化准则


  • 事例2

MySQL高级知识(七)——索引优化准则


  • 分析:
    • 对比事例1和事例2,事例1使用了select * ,事例2使用了覆盖索引(查询列和条件列对应),可看到extra从Null变成了Using index,提高了检索效率。

5. 使用不等于( !=或<>)会使索引失效

MySQL高级知识(七)——索引优化准则

结论:使用!=会使type=ALL,key=Null,导致全表扫描,并且索引失效。

6. is not null也无法使用索引

MySQL高级知识(七)——索引优化准则
结论:使用is not null的时候,type=ALL全表扫描,key=Null索引失效。

MySQL高级知识(七)——索引优化准则
此处type=ref,key=idx_name_age_pos,表明可以使用索引的。
注意:is null是可以使用索引的。

7. like通配符以%开头会使索引失效

  • 事例1

MySQL高级知识(七)——索引优化准则


  • 事例2

MySQL高级知识(七)——索引优化准则


  • 事例3

MySQL高级知识(七)——索引优化准则


  • 分析:
  1. like的%位置不同,所产生的效果不一样,当%出现在左边的时候,type=ALL,key=Null(全表扫描,索引失效),当%出现在右边的时候,type=range,索引未失效。

  2. like查询为范围查询,%出现在左边,则索引失效。%出现在右边索引未失效。口诀:like百分加右边。

  3. 但是在实际生产环境中,%仅出现在右边可能不能够解决我们的问题,所以解决%出现在左边索引失效的方法:使用覆盖索引。


  • 事例4

MySQL高级知识(七)——索引优化准则
分析:对比事例1可知,通过覆盖所有type=index,并使用了Using index,从全表扫描变成了全所以扫描,还是不错的。


  • 事例5

MySQL高级知识(七)——索引优化准则

分析:这里出现type=index,是因为主键自动创建唯一索引


  • 事例6
explain select age from staffs where staname like '%Jack%';
explain select staname,age from staffs where staname like '%Jack%';
explain select staname,age,pos from staffs where staname like '%Jack%';
explain select id,staname,age,pos from staffs where staname like '%Jack%';
---
explain select pos from staffs where staname like '%Jack%';  #结果也一样

MySQL高级知识(七)——索引优化准则
分析:上面四组explain执行的结果都相同,表明都使用了索引,从这里可以深刻的体会到覆盖所有:完全吻合或者沾边(age、pos),都可以使得type=index。


  • 事例7

MySQL高级知识(七)——索引优化准则
分析:由于只在(staname、age、pos)上面创建索引,当包含email时候,导致结果集偏大(email未建立索引)【锅大,锅盖小,不能匹配】,所以type=ALL。

8. 字符串不加单引号导致索引失效

MySQL高级知识(七)——索引优化准则

分析:

  1. 上述两条sql语句实际操作得到的数据是相同的。

  2. 通过explain执行结果可以看出,字符串(staname)不加单引号在查询的时候,导致索引失效(type=ref准变成了type=ALL,并且key=Null),并且全表扫描。

varchar类型的字段,在查询的时候不加单引号导致索引失效,转向全表扫描。
因为他可能会将这个转变类型。

9. 少用or,用or连接会使索引失效

MySQL高级知识(七)——索引优化准则

分析:通过上述explain的执行结果可以看出,在执行or连接的时候,type=ALL,key=Null,导致索引失效,并全表扫描。

总结:

  1. 全值匹配我最爱。

  2. 最佳左前缀法则: 带头大哥不能死,中间兄弟不能断;带头大哥可跑路,老二也可跟着跑,其余兄弟只能死。

  3. 索引列上不计算。

  4. 覆盖索引记住用。

  5. 不等于、is not null导致索引失效。

  6. like百分加右边,加左边导致索引失效,解决方法:使用覆盖索引。

  7. 字符串不加单引号导致索引失效。

  8. 少用or,用or导致索引失效。

相关文章:

  • 2021-10-20
  • 2021-09-05
  • 2021-11-02
  • 2021-12-31
  • 2022-12-23
  • 2021-09-17
  • 2021-10-24
猜你喜欢
  • 2022-12-23
  • 2021-09-23
  • 2022-12-23
  • 2021-06-15
  • 2021-07-04
  • 2021-05-21
相关资源
相似解决方案