索引失败的场景有哪些? 指数什么时候到期? (综合总结)

 2024-03-02 02:03:03  阅读 0

阅读本文大约需要 4 分钟。

从: ////

虽然你已经在该列上建立了索引,并且查询条件也是索引列,但是最终的执行计划并没有使用它的索引。 以下是导致此问题的几个关键点。

列与列的比较

在某个表中,两列(id 和 c_id)具有单独的索引。 以下查询条件不会被索引。

select * from test where id=c_id;

这种情况下认为最好进行全表扫描。

存在 NULL 值条件

在设计数据库表时,我们应该尽量避免NULL值。 如果NULL值不可避免,我们也应该给出一个值。 数字类型可以是0、-1等。 字符串有时会被赋予空字符串。 如果有问题,就给个空格什么的。 如果索引列可为空,则不会为其构建索引。 索引值小于表的count(*)值,所以在这种情况下,执行计划自然会扫描整个表。

select * from test where id is not null;

非条件

我们知道,在创建索引时,会为每个索引列创建一个条目。 如果查询条件是等值或范围查询,则索引可以根据查询条件找到对应的条目。 另一方面,当查询条件为NOT时,索引定位困难,此时执行计划可能更倾向于全表扫描。 此类查询条件包括:、NOT、in、not

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||'%',因为建立索引时,会从前面开始匹配索引列,此时就可以找到。 如果使用前置匹配,那么查找索引就会很麻烦。 例如,要查询所有姓张的人,可以搜索“张%”。 相反,如果查询所有名为“Ming”的人,那么只能是%Ming。 这个时候索引怎么定位呢? 在前面匹配的情况下,执行计划会更倾向于选择全表扫描。 匹配完成后,就可以使用INDEX RANGE SCAN。 因此,在业务设计时,尽量考虑模糊搜索问题,多使用后通配符。

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

有条件包含函数

查询条件中尽量不要对索引列使用函数,比如下面的SQL

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

这样就不会使用索引了,因为索引创建时和计算后可能不同,无法定位到索引。 但如果查询条件没有计算索引列,那么索引仍然可以使用。例如

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

此类函数还包括:、、、trunc等。

复合索引领先列区别大

当复合索引的前导列差异较小时,我们有INDEX SKIP SCAN。 目前的引导列分化较大,在检查后方引导列时,引导列的分裂会消耗大量的资源。 从执行计划来看,它不如全表扫描。 很快,然后索引就失效了。

select * from test where owner='sunyang';

数据类型转换

当查询条件存在隐式转换时,索引就会失效。 比如数据库中存储的是ID的类型,但是查询的时候却采用下面的形式:

select * from sunyang where id='123';

按级别

按级别使用时,不会使用索引。

谓词运算

上面我们说过,不能对索引列进行函数操作,其中还包括加减乘除的谓词操作,这也会使索引失效。 创建一个表,索引为id。 看看这个SQL:

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

这里很明显是对索引列id进行了'/2'除法运算。 这时,索引就会失效。 这种情况应该改写为:

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

您可以使用索引。

指数

首先说明一下,创建虚拟索引是否有用,取决于具体的执行计划。 如果可行,您可以构建一个。 如果它不起作用,那就忘记它吧。 一个普通的索引是这样构建的:

create index idx_test_id on test(id);

oracle索引是否生效_oracle中索引的作用_oracle 索引使用情况

虚拟索引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为虚拟索引。向表中插入10万条数据

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秒

因为执行一次后结果集就会被缓存,所以无论索引或内存使用情况如何,第二次执行时间都是相同的。 可以看到,在这种情况下,虚拟索引的速度是普通索引的两倍。 虚拟索引的具体使用细节这里不再讨论。

指数

Index是11g提供的新特性。 它对于优化器是不可见的(你还收到上一篇博客中提到的CBO吗)。 MySQL也有。 MySQL 8.0 中的索引可以隐藏。 我感觉这个功能主要是为了测试。 如果一张表的索引太多,逐一调试执行计划会非常慢。 这时候最好建一个对表和查询没有影响的索引,方便调试。 看起来很不错。使用下面的语句来操作索引

alter index idx_test_id invisible;
alter index idx_test_id visible;

如果想让CBO看到Index,需要加上这句话:

alter session set optimizer_use_invisible_indexes = true;

标签: mysql索引

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码