• 索引最左前缀原则


    通常我们在建立联合索引的时候,也就是对多个字段建立索引,相信建立过索引的同学们会发现,无论是oralce还是mysql都会让我们选择索引的顺序。

    比如我们想在a,b,c三个字段上建立一个联合索引,我们可以选择自己想要的优先级

    a、b、c,或者是b、a、c 或者是c、a、b等顺序。

    为什么数据库会让我们选择字段的顺序呢?不都是三个字段的联合索引么?这里就引出了数据库索引的最左前缀原理。

    比如:索引index1:(a,b,c)有三个字段,我们在使用sql语句来查询的时候,会发现很多情况下不按照我们想象的来走索引。

    比如:

    select * from table where c = '1'          这个sql语句是不会走index1索引的

    select * from table where b =‘1’ and c ='2' 这个语句也不会走index1索引。

    什么语句会走index1索引呢?

    答案是:

    select * from table where a = '1'  
    
    select * from table where a = '1' and b = ‘2’  
    
    select * from table where a = '1' and b = ‘2’  and c='3'
    
    

    我们可以发现一个共同点,就是所有走索引index1的sql语句的查询条件里面都带有a字段

    那么问题来了,index1的索引的最左边的列字段是a,是不是查询条件中包含a就会走索引呢?

    例如:select * from table where a = '1' and c= ‘2’这个sql语句,按照之前的理解,包含a字段,会走索引,但是是不是所有字段都走了索引呢?

    我们来做个实验:

    我这里有一个表:
    image.png

    建立了一个联合索引,prinIdAndOrder里面有三个字段 PARENT_ID, MENU_ORDER, MENU_NAME

    接下来测试之前的语句:

    select
    
      t.* 
    
    FROM
    
      sys_menu t 
    
    WHERE t.`PARENT_ID` = '0' 
    
      AND t.`MENU_NAME` = '系统工具'
    

    这一句sql就相当于之前的select * from table where a = '1' and c= ‘2’这个sql语句了,

    我们来看看解释计划:

    图为解释计划

    可以看到走了索引prinIdAndOrder,但是旁边的key_len=303,但道理key_len应该是大于303的,为什么呢?

    因为PARENT_ID字段的类型是varchar(100) NULL,所以key_len=100*3+2+1=303,但是还有MENU_NAME呢!

    具体的key_len的计算方法,大家可以百度,我的表的字符集是utf-8,不同字符集的表的计算方式不一样。

    这里的解释计划显示key_len只有303,说明只是走了字段PARENT_ID的索引,没有走MENU_NAME的索引。

    这也是最左前缀原理的一部分,索引index1:(a,b,c),只会走a、a,b、a,b,c 三种类型的查询,

    其实这里说的有一点问题,a,c也走,但是只走a字段索引,不会走c字段。

    总结:

    假设有如下表:

    create table
     AAA (a varchar(32) ,
    b varchar(32),
    c date);
    

    在a和c列上建普通索引:

    create index iN_AAA_1 on AAA (a, c);
    

    1.索引左前缀性的第一层意思

    必须用到索引的第一个字段。

    select * from AAA where b=:xxx and c=sysdate;则不会用到索引,因为必须有a出现在where 语句中才会使用到该索引。

    2.索引前缀性的第二层意思:

    对于索引的第一个字段,用like时左边必须是固定值,通配符只能出现在右边。

    select * from AAA where a like '1%';会用到索引;
    而select * from AAA where a like '%1';不会用到索引。

    3.索引前缀性的第三层意思:

    如果在字段前加了函数,则索引会被抑制,
    例如:select * from aaa where trim(a)=1,则不会用到索引。

    在字段前嵌入了表达式,索引也将被抑制。

    假设a是date格式的,那么where a+7<sysdate将不会用到索引,而where a<sysdate-7会用到索引。

     还有两个特殊声明:
    1).select * from AAA where a=:xxx and c=sysdate与 select * from AAA where c=sysdate and a=:xxx;都会用到索引,即与where语句中字段出现的顺序无关;

    2).select * from AAA where a=:xxx and b=1;会使用索引,只要有a字段,即时其它字段索引失效,也会用到a索引;

    我对任何唾手而得,快速,出自本能,即兴,含混的事物没有信心。我相信缓慢,平和,细水长流的力量,踏实,冷静。我不相信缺乏自律精神和不自我建设,不努力,可以得到个人或集体的解放。
  • 相关阅读:
    Help Hanzo (素数筛+区间枚举)
    How to create and apply a patch with Git
    Assembly
    GNU C 内联汇编介绍
    Arch Linux sudo: PAM authentication error: Module is unknown [Solved!]
    关于 RTL8723BS 同时开启 STA/AP 模式
    单源最短路径算法——Dijkstra算法
    Altium Designer PCB制作入门实例
    I2C 总线协议
    TarJan 算法求解有向连通图强连通分量
  • 原文地址:https://www.cnblogs.com/hellosiyu/p/13717014.html
Copyright © 2020-2023  润新知