网上有很多文章讲这个索引失效,最左匹配原则失效的,不能说他们说的不对,但却是不够全面的,如果拿网上大部分文章说的去面试的话,被面试官问多几个情况就会蒙住,以那些文章内的知识去根本不能做到举一反三。

今天我这里的是我个人实践后对索引失效,联合索引失效的总结

我使用的是MySQL5.6

目录

索引

最左匹配原则

联合索引

执行计划Extra字段


索引

索引列上不要使用表达式

mysql 在使用不等于(!= 或者<>)的时候无法使用索引,会导致全表扫描

is null 、is not null 也无法使用索引

like以通配符开头(’%abc…’),mysql索引会失效,会变成全表扫描的操作,不以通配符开头时可以

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

IN里的数量少会使用索引,数量多不会使用。或者mysql认为使用全表扫描要比使用索引快,数据太少或者查询出来的结果很多的时候会出现

如果一个索引包含所有需要的查询的字段的值,我们称之为覆盖索引。覆盖索引是非常有用的工具,能够极大的提高性能。因为,只需要读取索引,而无需读表,极大减少数据访问量并且速度更快

如果一个where条件可能命中多个索引,那么如果最终用上了索引,会使用最先创建的那个(与索引创建先后顺序有关,而与key_len大小无关)

 

最左匹配原则

说到最左匹配原则肯定就要说联合索引,那么究竟什么情况最左匹配原则会导致联合索引失效

网上的文章一般都会说

如果索引了多列(联合索引),要遵守最左前缀法则,指的是查询从索引的最左前列开始并且不跳过索引中的列,尤其是索引的头。就是最左优先,如果中间断开了,索引不会用全,如果不含第一个字段那么索引会失效

上面这种说法是不全面的!!注意!!如果不含第一个字段,当发生索引覆盖时,仍然会使用索引,下面来实践。

下图是我的一张表,user表,不需要关心表结构,只需要关注我创建的这些为了测试的单列索引或联合索引

mysql匹配like使用索引 mysql 索引匹配_左匹配

下图可看到,where条件只有age,password,但确实符合索引覆盖,select字段只有age和password。最终执行计划显示使用了u_a_p索引,从key_len可验证出是计算了username,age,password三个字段的(由于我没有放出表结构,这里告诉大家是正确的)。

 

mysql匹配like使用索引 mysql 索引匹配_联合索引_02

如果不是索引覆盖呢?

下图可见没有使用索引

mysql匹配like使用索引 mysql 索引匹配_mysql_03

从下两图可见,当where出现了联合索引的第一个字段的时候是遵循最左匹配原则的,中间断开了不连续则索引不会用全,从key_len可知,并且不管是否是索引覆盖都是如此

mysql匹配like使用索引 mysql 索引匹配_联合索引_04

mysql匹配like使用索引 mysql 索引匹配_mysql匹配like使用索引_05

 

最左匹配联合索引遇到like 通配符开头'%...',则使用like的字段不使用索引,其余如果符合可以,优化器会优化顺序

使用OR,当发生索引覆盖时,不管是否最左匹配,都会用到联合索引并且是所有字段用上通过key_len可知,不存在用不全的情况。但是当不是索引覆盖时,不会使用索引。下面实践

下图可见,where有两个字段,key_len为371

mysql匹配like使用索引 mysql 索引匹配_mysql_06

下图所示,不管是否最左匹配,都会用到联合索引并且是所有字段用上

mysql匹配like使用索引 mysql 索引匹配_联合索引_07

下图所示,当不是索引覆盖时,不会使用索引。

mysql匹配like使用索引 mysql 索引匹配_mysql_08

 

联合索引

使用联合索引的好处。

  1. 减少开销。建一个联合索引(col1,col2,col3),实际相当于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大的减少开销!
  2. 覆盖索引。对联合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。
  3. 效率高。索引列越多,通过索引筛选出的数据越少。有1000W条数据的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假设假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W10%=100w条数据,然后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,然后再排序,再分页;如果是联合索引,通过索引筛选出1000w10% 10% *10%=1w,效率提升可想而知!

 

 

执行计划Extra字段

  • using index :使用覆盖索引的时候就会出现
  • using where:在查找使用索引的情况下,需要回表去查询所需的数据
  • using index condition:查找使用了索引,但是需要回表查询数据 mysql5.6新增
  • using where;using index:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

using index condition官方解释:

Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from a table using an index. Without ICP, the storage engine traverses the index to locate rows in the base table and returns them to the MySQL server which evaluates the WHERE condition for the rows. With ICP enabled, and if parts of the WHERE condition can be evaluated by using only columns from the index, the MySQL server pushes this part of the WHERE condition down to the storage engine. The storage engine then evaluates the pushed index condition by using the index entry and only if this is satisfied is the row read from the table. ICP can reduce the number of times the storage engine must access the base table and the number of times the MysQL server must access the storage engine.

存储引擎通过使用索引条目来评估推送的索引条件,并且只有在满足此条件的情况下,才从表中读取行。 ICP可以减少存储引擎必须访问基表的次数以及MysQL服务器必须访问存储引擎的次数。

 

mysql匹配like使用索引 mysql 索引匹配_mysql_09

当使用了select * 或者含有某个字段不含在任何索引里,即便where条件命中了索引,extra都是using index condition,只有发生索引覆盖的时候才是using where;using index,明显using where;using index会优于using index condition,因为不用回表

 

关于Extra这部分研究得还不够深,欢迎大家交流

 

以上是我对索引,联合索引,最左匹配原则的理解和总结,欢迎大家交流和指正错误的地方。非常建议大家亲自去实践,避免被一些文章误导了。