浅谈MySQL的索引(2)

    上一篇我们从索引的存储结构分析,说到了B Tree索引、Hash索引、FULLTEXT全文索引。这一期,我们在从其他层次学习洗索引。


一、前期回顾

  • 从索引存储结构划分:B Tree索引、Hash索引、FULLTEXT全文索引以及R Tree索引

  • 从应用层次划分:普通索引、唯一索引、主键索引、复合索引

  • 从键值划分:主键、辅助

  • 从数据存储以及索引逻辑关系划分:聚集索引、非聚集索引


  • 二、索引的分类


    2.1、普通索引

            普通索引既我们平时常用的索引,默认使用的是BTree。

    ALTER TABLE `user`ADD INDEX `index_userNm` (`username`) USING BTREE COMMENT '用户名索引';-- 或者ALTER TABLE `user`ADD INDEX `index_userNm` (`username`);

    2.2、唯一索引

            与普通索引类似,不同的点在于:索引的值必须唯一,允许有空值。换句话说 某种程度上说的就是表中索引锁标记的唯一列。

    ALTER TABLE `user` ADD UNIQUE INDEX `index_un_id`(`id`);

    主键索引

            与唯一索引的区别就是索引标记的列不允许有空值,换句话说就是主键列上加的索引。

    ALTER TABLE `user` ADD PRIMARY KEY (`id`);

    2.3、复合索引

            又名联合索引,也是我们比较常用的索引类型之一。在数据表的2列或>2列共同组成的索引。而上面我们说的普通索引、唯一索引、主键索引又叫单一索引。顾名思义是指索引列只有一列,而用户可以在多个列上建立索引,这种索引就叫复合索引,也叫组合索引、联合索引,复合索引可以代替多个单一索引,相遇多个单一索引,复合索引所需的开销更小。


    在这里复合索引还有个小小的区分:窄索引、宽索引

    • 窄索引:指索引列为1-2列的索引

    • 宽索引:指索引列超过2列的索引

      索引设计原则:能用窄索引不用宽索引,因为窄索引往往比组合索引更有效


       值得我们重点关注的是:

  • 需要加索引的字段,要在where条件中。

  • 数据量少的字段不需要加索引。最窄的字段放在键的左边。

  • 如果where条件中是OR关系,必须所有的or条件都必须是独立索引,否则加索引不起作用。见:mysql关于or的索引问题

  • 左匹配原则。

  • 只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。


  • eg:

    假设某个表有一个联合索引(c1,c2,c3,c4)以下选项哪些字段使用了该索引:
    A where c1=x and c2=x and c4>x and c3=x
    B where c1=x and c2=x and c4=x order by c3
    C where c1=x and c4= x group by c3,c2
    D where c1=? and c5=? order by c2,c3
    E where c1=? and c2=? and c5=? order by c2,c3


    接下来借用上面的例子,我们求证一下:

  • 首先创建表:

  • CREATE TABLE t(  c1 CHAR(1) not null,  c2 CHAR(1) not null,  c3 CHAR(1) not null,  c4 CHAR(1) not null,  c5 CHAR(1) not null)ENGINE myisam CHARSET UTF8;

  • 创建索引:

  • alter table t add index c1234(c1,c2,c3,c4);

  • 随机搞两条数据:

  • insert into t VALUES('1','1','1','1','1'),('2','2','2','2','2')

  • 使用MySql Explain开始分析题目结果:

  • A 选项:where c1=x and c2=x and c4>x and c3=x



    说明下:UTF-8 编码,一个索引的长度为3,如上图我们可以看到,c1,c2,c3,c4均使用到了该索引。

    但是如果我们将查询条件调整下或者去掉一个,索引又是怎么使用的呢:





    由上面4个图可以看出,我们分别调整了各个列的位置,使用>和使用>的位置,发现索引都是正常使用的,所以可以得出:

  • 使用“<” / “>”并不影响索引的选择

  • where条件和创建索引的列保持一致时,条件的位置(顺序)并不影响索引的选择。


  • 但是,如果我们对A组where条件做些调整呢?




    当我们删除分别其中一个条件c1、c2、c3后,发现使用索引的个数也发生了变化。得出结论:

  • 当使用复合索引时,没有使用第一个复合索引,不触发索引的使用

  • 使用复核索引时,索引的选择与where的条件顺序和索引建立时的顺序是否一致存在关系,当顺序中断时,后续的索引列将不被选择。


  • 如果我们对A组where条件做些调整呢?








    当我们使用or,或者like时,通过上面4张图可以清醒的得出:

  • 当使用or时,不会使用索引

  • 当条件顺序与索引创建顺序一致,且使用 “like” / “like%”时,索引可以正常被选中

  • 当条件顺序与索引创建顺序一致,且使用 “%like%”,索引无法被选中

  • 当条件顺序与索引创建顺序不一致时,且第一个条件不是索引创建时的首列,则无法选中索引


  • B选项:where c1=x and c2=x and c4=x order by c3



    通过上图可以发现,key_len长度说明c1,c2字段用到了该索引,Extra显示并没有使用临时表进行排序,说明排序是使用了索引的,但并没有计算在key_len值中,也没有起到连接c4的作用,说明索引到c3这里是断掉的。

    排序其实是利用联合索引直接完成了的,即:使用了c1234联合索引,就已经使得c1下c2,c2下c3,c3下c4是有序的了,所以实际是排序利用了索引,c3字段并没有使用该索引。


    C选项:where c1=x and c4= x group by c3,c2



    通过上面两图,能看出使用group by 一般先生成临时文件,再进行排序,但是字段顺序为c2,c3时,并没有用临时表进行排序,而是利用索引排序好的;当group by字段为c3,c2时,由于与索引字段顺序不一致,所以分组和排序并没有利用到索引。


    D选项:where c1=? and c5=? order by c2,c3


    通过此图可以看出 order by 和group by 类似,字段顺序与索引一致时,会使用索引排序;字段顺序与索引不一致时,不使用索引。


    E选项:where c1=? and c2=? and c5=? order by c2,c3


    其实选项E的结果分析在上述ABCD的结果中都分析过了,这里只有c1,c2字段使用了该索引。

    综上所述问题答案:

        A:四个字段均使用了该索引

        B:c1,c2字段使用了该索引

        C:c1字段使用该索引

        D:c1字段使用该索引

        E:c1,c2字段使用了该索引

    三、小结:

  • 索引的最左原则(左前缀原则),如(c1,c2,c3,c4....cN)的联合索引,

  • where 条件按照索引建立的字段顺序来使用(不代表and条件必须按照顺序来写),

  • 如果中间某列没有条件,或使用like会导致后面的列不能使用索引。

  • 索引也能用于分组和排序,分组要先排序,在计算平均值等等。所以在分组和排序中,如果字段顺序可以按照索引的字段顺序,即可利用索引的有序特性。


  • 不知不觉写到这又有 2.5k 多字了,本期我们就写到这里,下期我们继续

    探讨索引。

    …………………………………分割线……………………………

    不积跬步,无以至千里;不积小流,无以成江海。

    关注我,每天分享一些小知识点。分享自己的小心得,包含但不限于初、中、高级面试题呦!!!

    我都墨迹这么半天了 ,你不点关注,不点赞,不收藏,还不转发,你想干啥!!!

    你可能感兴趣的:(浅谈MySQL的索引(2))