MySQL索引失效
MySQL索引失效
MySQL索引失效的情况
1)创建了组合索引,但查询条件未遵守最左匹配原则
2)在索引列上进行计算、函数、类型转换等操作
3)以%开头的LIKE查询比如LIKE '%abc';
4)查询条件中使用OR,且OR的前后条件中有一个列没有索引,涉及的索引都不会被使用到
5)IN的取值范围较大时会导致索引失效,走全表扫描(NOT IN和IN的失效场景相同)
6)发生隐式转换
违反最左前缀原则
假设有联合索引
1 | create index idx_abc on user(a, b, c); |
有效地情况:
1 | a |
无效的情况:
1 | b |
对索引列做了运算或函数
如:
1 | select * from user where age + 1 = 20; |
索引中存的是原始值,一旦对列进行运算,MySQL必须对每一行算一遍再比较,就相当于把有序结构打乱了,无法使用索引。
以%开头的LIKE查询
如:
1 | select * from user where name like '%abc'; |
B+Tree只能从左往右匹配
%abc没有前缀,所以无法使用索引
abc%有前缀,可以使用索引
OR条件中有一个列没有索引
如:
1 | select * from user where name = '张三' or age = 20; |
如果name列有索引,age列没有索引,那么这个查询就无法使用索引
解决方式:
- 给
age列也创建索引 - 或改成
UNION ALL的形式
IN的取值范围较大
如:
1 | select * from user where id in (1, 2, 3, ..., 1000); |
如果IN的取值范围较大,MySQL可能会认为使用索引不如全表扫描效率高,从而导致索引失效。
隐式转换
隐式转换规则:
- 两个参数至少有一个是
NULL时,比较的结果也是NULL,特殊的情况是使用<=>对两个NULL做比较时会返回1,这两种情况都不需要做类型转换 - 两个参数都是字符串,会按照字符串来比较,不做类型转换
- 两个参数都是整数,按照整数来比较,不做类型转换
- 十六进制的值和非数字做比较时,会被当做二进制串
- 有一个参数是
TIMESTAMP或DATETIME,并且另外一个参数是常量,常量会被转换为timestamp - 有一个参数是
decimal类型,如果另外一个参数是decimal或者整数,会将整数转换为decimal后进行比较,如果另外一个参数是浮点数,则会把decimal转换为浮点数进行比较 - 所有其他情况下,两个参数都会被转换为浮点数再进行比较
如:
1 | SELECT * FROM `test1` WHERE num2 = 10000; |
其中num2是字符串类型
左边是字符串类型'10000',转浮点数为10000是唯一的,右边int类型10000转换结果也是唯一的。但是,因为左边是检索条件,'10000'转到10000虽然是唯一,但是其他字符串也可以转换为10000,比如'10000a','010000','10000'等等都能转为浮点数10000,这样的情况下,是不能用到索引的。
