[转]正确理解与使用mysql索引
转自: http://terry831010.blog.163.com/blog/static/69161171201382011498834/
项目中,发现经常有人弄错索引,不是没有命中索引,就是建了一堆多余的索引浪费空间。 对于索引,只有正确理解后才能正确使用。
以下几个问题,如果能快速回答,请略过。
表a, 字段: id(自增id),user(用户名),pass(密码),type(类型 0,1),
索引: user + pass 建立联合索引 ,user唯一索引,pass普通索引 ,type 普通索引
1 、SQL: SELECT * FROM a WHERE user = 'terry' AND PASS = 'nndhsbd1243AC'
会命中哪个索引?
2、SQL: SELECT * FROM a WHERE user = 'terry' OR user= 'frank'
会命中哪个索引?
3、SQL: SELECT * FROM a WHERE user = 'terry'
会命中哪个索引?
4、SQL: SELECT * FROM a WHERE pass = 'ssssssssss' 会命中哪个索引?
5、哪些索引是多余的
6、
SELECT * FROM a WHERE user = 'terry' OR user= 'frank' 与
SELECT user,pass FROM a WHERE user = 'terry' OR user= 'frank'
哪个快,为什么?
7、SELECT * FROM a WHERE length(user) = 3 能命中索引吗?
1、user+pass的联合索引,2、不能命中任何索引,3、user唯一索引 4、不能命中任何索引 5、user唯一索引 、type索引可以删除
6、后者更快,因为符合索引覆盖,减少了IO . 7 不能。索引列需要隔离
为什么?
索引就是排序,目前的计算机技术和数学理论还不支持一次同时按照两个关键字进行排序,即使是联合索引,也是先按照最左边的关键字先排,然后在左边的关键字排序基础上再对其他的关键字排序,是一个多次排序的结果。 所以,单表查询,一次最多只能命中一个索引,并且索引必须遵守最左前缀 。 可以想象字典的拼音目录,他是典型的索引,先按照首字母,然后按次字母排序。如果你知道首字母可以很快查询到,但是如果只知道最后一个字母,你仍然需要遍历全表。这就是最左前缀的通俗理论。于是基于索引的结构和最左前缀,像 OR , like '%%' ,都是不能命中索引的,而 like 'aa%'则是可以命中的。
无论是innodb还是myisam,索引只记录被排序的行的主键或者地址,其他的字段还是需要二次查询,因此,如果查询的字段刚好只是包含在索引中,那么索引覆盖将是高效的。
尽然是排序,那么需要考虑选择性,如果所有的数据都一样,或者基本一样,那么就没有排序的必要了。像例子中的type只有1或者0,选择性是0.5,极低的样纸,所以可以忽视,即使建立了,也是浪费空间,mysql在查询的时候也会选择丢弃。
类似最左前缀,查询索引的时候,如果列被应用了函数,那么在查询的时候,是不会用到索引的。道理很简单,函数运算已经改变了列的内容,而原始的索引是对列内容全量排序的。
综上所述,索引的几个知识点:最左前缀,索引覆盖,索引选择性,列隔离在建立和使用索引的时候需要格外注意。