在MySQL中,如果需要查找某一行的值,可以先通过索引找到对应的值,然后根据索引匹配的记录找到需要查询的数据行。然而,有些时候,即使查询条件有索引,也会查询很慢,那是因为查询条件的错误使用导致没有正确利用到索引,即有索引,但是查询时没走索引。那么都有哪些条件字段有索引但是不走索引的场景呢?如下:
比如:查询测试表t1某一天的所有数据,SQL如下:
select * from t1 where date(c) ='2019-05-21';
使用explain来分析这条SQL语句,如下:
explain select * from t1 where date(c) ='2019-05-21';
分析结果如下:
可以看出,type为ALL,key字段结果为Null,rows为10302,因此知道该SQL语句是没走索引的全表扫描。
select * from t1 where date(c) ='2019-05-21';
select * from t1 where c>='2019-05-21 00:00:00' and c<='2019-05-21 23:59:59';
select tele_phone from user_info where tele_phone =11111111111;
查询的时候,mysql会将tele_phone条件对应的值隐式转化为varchar类型,这样即便我们的条件值是int类型的,实际查询的时候也是按照varchar类型作为条件。
比如:查询测试表t1字段a为1000的记录,其中a字段是varchar类型,SQL执行计划如下:
explain select * from t1 where a = 1000;
分析结果如下,type为ALL,rows为10302所有行,key为null,说明没走索引:
t1表中a字段是varchar类型,而查询字段没有加单引号,导致MySQL会先将a字段转换成int类型再去查询,相当于执行SQL语句如下:
select * from t1 where cast(a as signed int) =1000;
因此,隐式转换相当于一次隐式的计算操作,上面说到计算操作不走索引,因此隐式转换也不走索引。
·
explain select * from t1 where a = '1000';
分析结果如下,type为ref,key为idx_a,rows为1,表示走了索引:
比如:查询t1表中包含1000的记录,SQL执行计划如下:
explain select * from t1 where a like '%1000%';
分析结果如下,发现是全表扫描,不走索引:
当like的通配符条件为 '1000%'
时的SQL执行计划如下:
explain select * from t1 where a like '1000%';
分析结果如下,这种条件下是走索引的,但是查询的是以1000开头的数据:
虽然查询条件前面不写通配符的操作可以走索引,但是得结合实际使用,避免查询到脏数据。如果只知道中间的值,需要模糊查询,那么可以使用ES等专门的查询引擎。
通常情况下,范围查询是可以走索引的,但是在一定情况下,即便是条件字段有索引,但是却还是走全表扫描了,比如:查询出t1表中b字段1到2000范围的数据,其中b的类型是int,SQ执行计划如下:
explain select * from t1 where b>=1 and b <=2000;
分析结果如下,可以看出没走索引:
之所以没走索引,是因为MySQL优化器根据检索比例、表大小进行评估是否使用索引,如果单次查询量过大,优化器将不走索引。
本文讲解了4种不能走索引的查询场景,针对这些场景应该注意一下几点: