索引失效的狀況有哪些?索引什麼時候會失效?(全面總結)

雖然你這列上建了索引,查詢條件也是索引列,但最終執行計劃沒有走它的索引。下面是引發這種問題的幾個關鍵點。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開發手冊(嵩山版)》最新發布,速速下載!

以爲不錯,別忘了隨手點贊+轉發哦!

相關文章
相關標籤/搜索