mysql索引的要点分析

北慕城南 提交于 2019-11-28 14:56:11

mysql的索引并不是很好总结,所以日常工作中大家应该多使用 explain 来优化自己的查询和索引,做到用最少的索引来配合最高效的查询语句完整业务需求,这里我总结一些平日里遇到的比较多变的索引问题:组合索引的设计问题, order by 如何利用索引

1、最左前缀原则

    应用场景:频繁对多列进行联合检索,可做组合索引

    

    例如我们创建了 name email nick 的组合索引 name_email_nick

    要想使用此索引则必须遵循 最左前缀 原则,说的简单些就是 检索条件集 可以从左到右的优先级次序匹对 组合索引的列序

    

    可以看出组合索引其实是为每一个子列建立的索引,然后以 seq_in_index 的位序连接在一起,当你想让自己的查询能启用此索引,则最基本的一条就是最左前缀,按位序可以依次满足,中间不存在位序间断

    拿此例来说,左前缀的组合方式有(注意,这里是条件集的最终拼接结果,并不是条件位序):

1    1,2    1,2,3

    而

2    3    2,3

    都不满足最左前缀原则

    实例:

    name 使用一个

    

    name email 使用两个

    

    name email nick 使用三个

    

    再次强调最左前缀与检索条件的书写顺序无关,只要能满足从左开始不间断的满足组合索引的子列位序即可

    

    如上图所示,检索条件的位序虽然与组合索引的不同,但并不影响

    最左前缀:检索条件集合可以按组合索引列序无间断的排列出连续的位序列,则可使用此索引,否则无法使用此索引

    

    如上图所示,检索条件只有 email 和 nick,无法有序的组成复合组合索引 name email nick 的不间断序列,缺失 name 位序,所以无法使用索引

    

加上 name 即可使用

2、最小资源原则

    这个比较容易理解,mysql 会优先使用 精确度高 的索引,因为每次查询只能使用一个索引,所以这里会有择优算法

    

    虽然检索条件符合 primary key 和 name_email_nick 的组合索引使用条件,但主键可以精准定位一条记录所以会使用 主键 而非 组合索引列,这里也再次证明 检索条件的位序和索引位序没什么关系

3、组合索引的本质

    组合索引的本质其实是mysql为每组合列各添加索引,然后用位序标定他们,组合索引其中的某列索引 和 为此列单独添加的普通索引本质上没有区别,如下:

    我先添加的 name_email_nick 组合索引

    我再为 name 列单独添加一普通索引

    

    

    我删掉 name_email_nick 组合索引然后再添加它,这样就相当于 普通的 name 索引时序先于 含有 name 的组合索引了

    

    

    因为我的查询条件只有 name,所以对普通索引 name 和 组合索引 name_email_nick 来说他们所能定位的资源精确度是相等得,而后普通索引 name 与 组合索引中的 name列索引此时属于对等,所以 mysql 就按照谁先创建的就使用谁,此时如果使用 name_email_nick 其实也只是使用其中的 name 列索引,和我们后来添加的 name 的普通索引本质上没有任何区别

4、索引优化之 order by

    网上很多博文说如果检索中有使用 order by 进行检索时,在 order by 列上加索引就会被启用,但据我实测,order by 会使用索引只有以下几种情况

    首先明确,每一次的检索 mysql 只会选用一个索引

    1、当 order by 与 limit 结合时也会有可能启用索引,是有可能,因为 limit 其本质上是在我 order by 的结果集上做范围查询,但也是有限定范围的,当你的 limit 跨度太大mysql仍然不会使用索引,因为代价几乎与Using filesort对等了

   2、 还有一种情况就有些没逻辑了:当 select 的字段与 order by 字段完全吻合时会使用索引......这点我也不知道怎么讲,但 select col from table order by col;真的会使用 col 的索引,即便你不与 limit 联合使用

    3、至于很多人说在 order by 作用的列上加索引就会被启用,那应该是他们的sql中在 where 条件里有 相同列 而已,真正的索引是在 where 里被启用而不是 order by

    

    索引建立如下

    

    1、不配合范围或等值查询,完全查询本表,不启用索引

        网上很多博文说 order by 所作用的列如果有索引便会启用,其实是不准确的,他们得出的结论其实是被 where 条件中的列索引影响了

        

        

        但如果你只是选择读取与order by 一致的列则可以启用索引

        

        那怎样在日常较为普遍的查询中优化 order by 呢,简单,在 order by 作用的列上加索引后 使用  limit 做辅助查询,但这个范围不能太大,否则索引和遍历整张表没什么区别了,这也是分页的精髓所在,因为 limit 也是一范围,会使用 BTREE 索引做范围查询

         

    2、与 where 联用

    感觉与where联用不联用没什么要说的,你只要记住mysql每次查询时只会使用一个索引,如果where中启用索引了order by 即便和 limit 联合也会使用 Using filesort 了

5、使用索引需要注意的几点

    常用索引方式分为 HASH 索引 和 B-TREE 索引

     HASH 索引

    HASH 索引即散列索引,通过散列函数准确的定位出地址,仅适用于 MEMORY 引擎的的表,是无序的,通过 HASH 函数计算出其在内存中的位置,所以只能做精确的=值查询,没办法高效的做范围查询。

    B-TREE 索引

    B-TREE 索引则是有序的,适合 MyISAM InnoDB等引擎,可以做=值,范围(>, <, >=, <=, between, in,limit),但不支持 not in, <> 等查询,因为不等查询肯定会遍历全表,只有遍历到最后一条记录时我才能确定本表中还有无与条件相符的记录。


    索引使用注意项

    1、索引不作用于存在 NULL 值的列,所以建议大家在定义列时指定 NOT NULL DEFAULT val

    2、索引不作用于参与函数运算的列 , 即便 BIRTHDAY 上加了索引,但函数作用在此列上索引失效

SELECT * FROM TABLE WHERE BIRTHDAY >= UNXI_TIMESTAMP('1990-03-07');

    3、索引可以做 等值 范围 查询,不可做不等查询

/*无法启用索引*/
SELECT * FROM TABLE WHERE ID <> 1;
SELECT * FROM TABLE WHERE ID NOT IN(1, 3, 5, 7);

    4、like 做模糊查询时

/*可使用索引*/
SELECT * FROM TABLE WHERE `name` LIKE 'sallen%';
/*不可使用索引*/
SELECT * FROM TABLE WHERE `name` LIKE '%sallen%';

    5、经常与其他表进行连接的表,在连接字段上应该建立索引

    6、频繁进行数据操作的表,不要建立太多的索引,因为 增删改 都会对索引做更新,这样会加重mysql的负担

    

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!