索引失效的状况有哪些?索引什么时候会失效?(全面总结)

虽然你这列上建了索引,查询条件也是索引列,但最终执行计划没有走它的索引。下面是引发这种问题的几个关键点。java

列与列对比

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

select * from test where id=c_id;

这种状况会被认为还不如走全表扫描。spring

存在NULL值条件

咱们在设计数据库表时,应该尽力避免NULL值出现,若是非要不可避免的要出现NULL值,也要给一个DEFAULT值,数值型能够给0、-1之类的, 字符串有时候给空串有问题,就给一个空格或其余。若是索引列是可空的,是不会给其建索引的,索引值是少于表的count(*)值的,因此这种状况下,执行计划天然就去扫描全表了。数据库

select * from test where id is not null;

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);

LIKE通配符

当使用模糊搜索时,尽可能采用后置的通配符,例如:name||’%’,由于走索引时,其会从前去匹配索引列,这时候是能够找到的,若是采用前匹配,那么查索引就会很麻烦,好比查询全部姓张的人,就能够去搜索’张%’。session

相反若是你查询全部叫‘明’的人,那么只能是%明。这时候索引如何定位呢?前匹配的状况下,执行计划会更倾向于选择全表扫描。后匹配能够走INDEX RANGE SCAN。intellij-idea

因此业务设计的时候,尽可能考虑到模糊搜索的问题,要更多的使用后置通配符。oracle

select * from test where name like 张||'%';

条件上包括函数

查询条件上尽可能不要对索引列使用函数,好比下面这个SQLless

select * from test where upper(name)='SUNYANG';

这样是不会走索引的,由于索引在创建时会和计算后可能不一样,没法定位到索引。但若是查询条件不是对索引列进行计算,那么依然能够走索引。好比ide

select * from test where name=upper('sunyang');
--INDEX RANGE SCAN

这样的函数还有:to_char、to_date、to_number、trunc等

复合索引前导列区分大

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

select * from test where owner='sunyang';

数据类型的转换

当查询条件存在隐式转换时,索引会失效。好比在数据库里id存的number类型,可是在查询时,却用了下面的形式:

select * from sunyang where id='123';

Connect By Level

使用connect by level时,不会走索引。

谓词运算

咱们在上面说,不能对索引列进行函数运算,这也包括加减乘除的谓词运算,这也会使索引失效。创建一个sunyang表,索引为id,看这个SQL:

select * from sunyang where id/2=:type_id;

这里很明显对索引列id进行了’/2’除二运算,这时候就会索引失效,这种状况应该改写为:

select * from sunyang where id=:type_id*2;

就能够使用索引了。

Vistual Index

先说明一下,虚拟索引的创建是否有用,须要看具体的执行计划,若是起做用就能够建一个,若是不起做用就算了。
普通索引这么建:

create index idx_test_id on test(id);

虚拟索引Vistual Index这么建:

create index idx_test_id on test(id) nosegment;

作了一个实验,首先建立一个表:

CREATE TABLE test_1116( 
id number, 
a number 
); 

CREATE INDEX idx_test_1116_id on test_1116(id); 
CREATE INDEX idx_test_1116_a on test_1116(a)nosegment;

其中id为普通索引,a为虚拟索引。

在表中插入十万条数据

begin 
for i in 1 .. 100000 loop 
        insert into test_1116 values (i,i); 
end loop; 
commit; 
end;

接着分别去执行下面的SQL看时间,因为在内网机作实验,图贴不出来,数据保证真实性。

select count(id) from test_1116;
--第一次耗时:0.061秒
--第二次耗时:0.016秒

select count(a) from test_1116; 
--第一次耗时:0.031秒
--第二次耗时:0.016秒

由于在执行过一次后,oracle对结果集缓存了,因此第二次执行耗时不走索引,走内存就都同样了。
能够看到在这种状况下,虚拟索引比普通索引快了一倍。

具体虚拟索引的使用细节,这里再也不展开讨论。

Invisible Index

Invisible Index是oracle 11g提供的新功能,对优化器(还接到前面博客里讲到的CBO吗)不可见,我感受这个功能更主要的是测试用,假如一个表上有那么多索引,一个一个去看执行计划调试就很慢了,这时候不如建一个对表和查询都没有影响的Invisible Index来进行调试,就显得很好了。

经过下面的语句来操做索引

alter index idx_test_id invisible;
alter index idx_test_id visible;

若是想让CBO看到Invisible Index,须要加入这句:

alter session set optimizer_use_invisible_indexes = true;

原文连接:https://blog.csdn.net/bless20...

版权声明:本文为CSDN博主「番茄发烧了」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处连接及本声明。

近期热文推荐:

1.600+ 道 Java面试题及答案整理(2021最新版)

2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

3.阿里 Mock 工具正式开源,干掉市面上全部 Mock 工具!

4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

以为不错,别忘了随手点赞+转发哦!

相关文章
相关标签/搜索