zoukankan      html  css  js  c++  java
  • MySQL高级知识(六)——索引优化

    前言:索引优化的目的主要是让索引不失效,本篇通过相关案例对索引优化进行讲解。


    0.准备

    创建经典的tb_emp表。

    DROP TABLE IF EXISTS `tb_emp`;
    CREATE TABLE `tb_emp` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) NOT NULL,
      `age` int(11) NOT NULL,
      gender varchar(10) NOT NULL,
    email varchar(20),
    PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ---------------------------- INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Tom', '22','male','1@qq.com'); INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Mary', '21','female','2@qq.com'); INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Jack', '27','male','3@qq.com'); INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Rose', '23','female','4@qq.com');

    注:创建了tb_emp表,并插入了4条数据。

    1.最佳左前缀法则

    #1.定义:在创建了多列索引的情况下,查询从索引的最左前列开始且不能跳过索引中的列

    最佳左前缀法则就是说如果创建了多个索引,在使用索引时要按照创建索引的顺序来使用,不能缺少或跳过,当然如果只使用最左边的索引列,也就是第一个索引是可以的,通俗理解:“带头大哥不能死,中间兄弟不能断”。要点:“头不能掉”。下面将用案例进行说明。

    #2.创建组合索引,并执行explain。

    Case 1:

    分析:

    ①索引的创建顺序为name,age,gender;

    ②直接使用name(带头大哥)作为条件,可以看到type=ref,key_len=82,ref=const,效果还不错。

    Case 2:

    分析:

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

    Case 3:

    分析:

    ①对比上面两句sql语句可发现:我们使用:火车头(name)和中间车厢(age)、火车头(name)和车尾(gender)

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

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

    Case 4:

    分析:

    火车头加车厢加车尾,三者串联,就变成了奔跑的小火车。type=ref,key_len=128,ref=const,const,const。

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

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

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

    Case 1:

    分析:

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

    Case 2:

    分析:

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

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

    3.范围右边全失效

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

    Case 1:

    Case 2:

    Case 3:

    Case 4:

    对以上4个case进行分析:

    ①条件单独使用name时,type=ref,key_len=82,ref=const。

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

    ③当全值匹配时,type=ref,key_len=128,ref=const,const,const。说明索引全部用上,从key_len与ref可以看出。

    ④当使用范围时(age>27),type=range,key_len=86,ref=Null,与Case 1、Case2和Case3可知,使用了部分索引,但gender索引没用上(与Case 3对比)。

    结论:范围右边的索引列失效

    4.尽量使用覆盖索引

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

    Case 1:

    Case 2:

    分析:

    对比Case1和Case2,Case1使用select *,Case2使用覆盖索引(查询列与条件列对应),可看到Extra从Null变成了Using index,提高检索效率。

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

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

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

    Case 1:

    Case 2:

    分析:

    在使用is null的时候,索引完全失效,使用is not null的时候,type=ALL全表扫描,key=Null索引失效。

    这里的例子可能有点特殊,具体情况肯能和case上的有所不同,但是还是要注意is null和is not null的使用。

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

    Case 1:

    Case 2:

    Case 3:

    分析:

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

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

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

    Case 4:

    分析:对比Case1可知,通过覆盖索引type=index,并且使用了Using index,从全表扫描变成了全索引扫描,还是不错的。

    Case 5:

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

    Case 6:

    分析:上面四组explain执行的结果都相同,表明都使用了索引,从这里可以深刻的体会到覆盖索引:完全吻合或者沾边(age),都可以使type=index。

    Case 7:

    分析:由于只在(name,age,gender)上创建索引,当包含email时,导致结果集偏大(email未建索引)【锅大,锅盖小,不能匹配】,所以type=ALL。

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

    Case 1:

    分析:上述两条sql语句都能查询出相同的数据。

    Case 2:

    分析:

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

    结论:varchar类型的字段,在查询的时候不加单引号导致索引失效,转向全表扫描

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

    结论:通过上述explain的执行结果可看出,在使用or连接的时候type=ALL,key=Null,索引失效,并全表扫描

    总结

    ①全值匹配。

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

    索引列上不计算

    覆盖索引记住用

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

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

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

    少用or,用or导致索引失效


    by Shawn Chen,2018.6.25日,上午。


    相关内容

    MySQL高级知识系列目录

  • 相关阅读:
    flume sink两种类型 file_rool 自定义sing com.mycomm.MySink even if there is only one event, the event has to be sent in an array
    为什么引入进程20年后,又引入线程?
    As of Flume 1.4.0, Avro is the default RPC protocol.
    Google Protocol Buffer 的使用和原理
    Log4j 2
    统一日志 统一订单
    网站行为跟踪 Website Activity Tracking Log Aggregation 日志聚合 In comparison to log-centric systems like Scribe or Flume
    Percolator
    友盟吴磊:移动大数据平台的架构、实践与数据增值
    Twitter的RPC框架Finagle简介
  • 原文地址:https://www.cnblogs.com/developer_chan/p/9219934.html
Copyright © 2011-2022 走看看