专题讨论【索引失效】

导致sql语句跳过索引,直接全表搜索的情况

1。第一种数据量问题超过一定数据量导致索引失效,直接跳过索引全表扫描

这里有一个有意思的问题,那就是其实我的表里边create_time字段是加了索引的,但可以看到type=ALL,说明没有使用到索引,这是为什么呢?

开始我以为是< >符号的问题,因为我看一篇博客上说,sql语句使用< >符号,会导致全部搜索,于是我改用between...and...语法

explain SELECT * from ord_order_consume where create_time between ‘2020-04-01 00:00:00‘ and ‘2020-07-23 23:59:59‘

查询结果

 

 

 

 发现type仍然是ALL,没有使用索引,说明这里跟< >符号没有关系

但是,当我将日期范围调小之后

explain SELECT * from ord_order_consume where create_time > ‘2020-06-01 00:00:00‘ and create_time < ‘2020-07-23 23:59:59‘

查询结果

 

 

 

 发现type变为了range,并且key也有索引的名称,说明使用了索引

由此得出结论

当时间类型的字段存在索引时,索引是否使用与查询到的数量大小有关

查询到的数量大,不使用索引;

查询到的数量小,使用索引;

至于这个数量是什么范围,好像是有一个比例.不过我大致测了一下,如果查询结果在两万左右,会使用索引,再大就不再使用索引了(这里仅做参考)

2.查询条件索引字段使用了!=会导致索引失效

第二步:失效的索引。

1、使用语句:

explain select * from p_user WHERE name != 'A'

怎么判断mysql中sql语句索引是否生效

3. 同时使用了有效和无效,索引会依然有效

1、使用语句:

explain select * from p_user WHERE name='B' AND name != 'A'

怎么判断mysql中sql语句索引是否生效

 

4.使用or  导致索引失效

1.where条件查询语句带or,只要带or,即使其中的查询条件包含有索引的字段,也会导致索引失效,除非查询条件的字段都带索引(注意:主键自带索引,属于唯一索引的特定类型)

explain select * from ord_order_consume where user_id = 1349813 or buss_type = 2

结果

 

 5.复合索引状态:

对于复合索引,如果查询条件不是第一个索引字段,那么不会使用索引

 

explain select * from ord_order_consume where create_time = ‘2020-06-01 00:00:00‘
可以看到生效了

 

 

 如果使用orderstate索引失效

explain select * from ord_order_consume where order_state = 20

 

 

3.like模糊查询,%在左边(查了不少资料,说%在右边不会导致索引失效,但我实践了一下,发现也失效了,具体原因有待进一步研究)

explain select * from ord_order_consume where stake_no like ‘%1‘

结果

 

 

 

4.where查询条件字段如果是varchar类型,必须用引号引起来,否则索引失效

explain select * from ord_order_consume where stake_no  = 1140290000001466

 

 

 

 

 

 select * from ord_order_consume where stake_no = ‘1140290000001466‘

 

 

列与列对比
某个表中,有两列(id和c_id)都建了单独索引,下面这种查询条件不会走索引

select * from test where id=c_id;
1
这种情况会被认为还不如走全表扫描。

存在NULL值条件
我们在设计数据库表时,应该尽力避免NULL值出现,如果非要不可避免的要出现NULL值,也要给一个DEFAULT值,数值型可以给0、-1之类的, 字符串有时候给空串有问题,就给一个空格或其他。如果索引列是可空的,是不会给其建索引的,索引值是少于表的count(*)值的,所以这种情况下,执行计划自然就去扫描全表了。

select * from test where id is not null;
1
NOT条件
我们知道建立索引时,给每一个索引列建立一个条目,如果查询条件为等值或范围查询时,索引可以根据查询条件去找对应的条目。反过来当查询条件为非时,索引定位就困难了,执行计划此时可能更倾向于全表扫描,这类的查询条件有:<>、NOT、in、not exists

select * from test where id<>500;
select * from test where id in (1,2,3,4,5);
select * from test where not in (6,7,8,9,0);
select * from test where not exists (select 1 from test_02 where test_02.id=test.id);
1
2
3
4
LIKE通配符
当使用模糊搜索时,尽量采用后置的通配符,例如:name||’%’,因为走索引时,其会从前去匹配索引列,这时候是可以找到的,如果采用前匹配,那么查索引就会很麻烦,比如查询所有姓张的人,就可以去搜索’张%’。相反如果你查询所有叫‘明’的人,那么只能是%明。这时候索引如何定位呢?前匹配的情况下,执行计划会更倾向于选择全表扫描。后匹配可以走INDEX RANGE SCAN。
所以业务设计的时候,尽量考虑到模糊搜索的问题,要更多的使用后置通配符。

select * from test where name like 张||'%';
1
条件上包括函数
查询条件上尽量不要对索引列使用函数,比如下面这个SQL

select * from test where upper(name)='SUNYANG';
1
这样是不会走索引的,因为索引在建立时会和计算后可能不同,无法定位到索引。但如果查询条件不是对索引列进行计算,那么依然可以走索引。比如

select * from test where name=upper('sunyang');
--INDEX RANGE SCAN
1
2
这样的函数还有:to_char、to_date、to_number、trunc等

复合索引前导列区分大
当复合索引前导列区分小的时候,我们有INDEX SKIP SCAN,当前导列区分度大,且查后导列的时候,前导列的分裂会非常耗资源,执行计划想,还不如全表扫描来的快,然后就索引失效了。

select * from test where owner='sunyang';
1
数据类型的转换
当查询条件存在隐式转换时,索引会失效。比如在数据库里id存的number类型,但是在查询时,却用了下面的形式:

select * from sunyang where id='123';

posted @ 2021-08-11 11:09  不带R的墨菲特  阅读(99)  评论(0编辑  收藏  举报