索引失效的幾種情況


1.查詢的數量是大表的大部分

說明:單次查詢如果查出表的大部分數據,這會導致編譯器認為全表掃描性能比走索引更好,從而導致索引失效。一般單次查詢數量大概占大表的30%以上索引會失效。

 

2.索引本身失效

說明:索引需要定期重建。

重建索引的原因主要包括:

1、 刪除的空間沒有重用,導致索引出現碎片

2、 刪除大量的表數據后,空間沒有重用,導致索引"虛高"

3、索引的 clustering_facto 和表不一致

 

3.查詢條件使用函數在索引列上

select * from test where round(id)=10;   此時id的索引已經不起作用了.

正確的例子:

首先建立函數索引:create index test_id_fbi_idx on test(round(id)); 
然后 select * from test where round(id)=10;

這時函數索引起作用了 .

 

4.對小表查詢

說明:對於數據量較少的表,本身不需要創建索引,如果建立了索引,索引未必生效。

 

5.提示不使用索引

說明:SQL執行時強行指定不走索引。

 

6.統計數據不真實或者表沒分析

說明:數據庫會定時對表進行分析,如果表過大導致分析計划沒有及時跑完,或者由於其他原因導致統計數據不真實,這樣會導致CBO計算走索引花費不准確的情況,可能會導致不走索引而使用全表掃描。這也是為什么當表的數據量達到一定級別的時候,我們建議進行分表分庫,因為表數據量過大,可能導致表分析過程沒有執行完成。

 

7.隱式轉換導致索引失效

這一點應當引起重視,也是開發中經常會犯的錯誤.。由於表的字段tu_mdn定義為varchar2(20), 但在查詢時把該字段作為number類型以where條件傳給Oracle,這樣會導致索引失效.。
錯誤的例子:select * from test where tu_mdn=13333333333; 
正確的例子:select * from test where tu_mdn='13333333333'; 

 

8.對索引列進行運算導致索引失效

對索引列進行運算包括(+,-,*,/,! 等) 
錯誤的例子:select * from test where id-1=9; 
正確的例子:select * from test where id=10; 

 

9.where 子句中使用<>或者!=

說明:形如select * from table where id <>1 這樣的情況一般不走索引。

 

10.like "%****" 百分號在前(like '%XX'或者like '%XX%')

說明:

select * from table where name like ‘%aaa’   不走索引

select * from table where name like 'aaa%'  走索引

 

11.單獨引用復合索引里非第一位置的索引列

說明:索引遵循最左原則,形如ABC的復合索引如果單獨使用B或者C則不走此復合索引。

復合索引 :ABC

引用情況:  ABC(走ABC復合索引) AB(走AB聯合索引)      AC(使用索引A)      BC(不使用索引)    A(使用索引A)     B(不使用索引)     C(不使用索引)

 

12.not in ,not exist

說明:使用not in ,not exist一般不走索引。

在使用 not in 的時候,需要保證子查詢的匹配字段是非空的。如若不然,就會導致 not in 返回的整個結果集為空。

 

13.is null,is not null

B-tree索引 is null不會走,is not null會走,位圖索引 is null,is not null 都會走 聯合索引的not NULL比較麻煩,實際需要測試,聯合索引is not null會走索引,同樣也需要滿足最左原則。

 

14.條件中有or

select * from table where id = 10 or pid = 10 ;   此類查詢必須滿足id和pid均有索引,如果只是id或者pid存在索引,則索引不生效。

可以改為:

select * from table where id = 10   union select * from table where  pid = 10 ; 這樣的話,就不需要滿足id和pid均有索引的條件。

 

15.in,exists

in:   select * from t1 where id in (select id from t2);

大表 t2 做外表還是內表,都會走索引的,小表 t1 做內表時也會走索引,小表t1做外表不走索引

exists:   select * from t1 where exists (select 1 from t2 where t1.id=t2.id);

t1 表哪種情況都不會走索引,而 t2 表是有索引的情況下就會走索引。

最終結論: 外層大表內層小表,用in。外層小表內層大表,in和exists效率差不多(甚至 in 比 exists 還快,而並不是網上說的 exists 比 in 效率高)。

PS:使用in需要注意,如果內層不是子查詢,而是我們組織出來的數據比如 select * from table where id in (1,2,3,4,5...........) 則內層數據每次查詢不能超過1000個,否則會導致SQL執行緩慢,對於部分國產數據庫甚至可能出現卡死。

select * from t1 where name in (select name from t2);

對於 in 查詢來說,會先執行子查詢,如上邊的 t2 表,然后把查詢得到的結果和外表 t1 做笛卡爾積,再通過條件進行篩選(這里的條件就是指 name 是否相等),把每個符合條件的數據都加入到結果集中。

for(x in A){
    for(y in B){
     if(condition is true) {result.add();}
    }
}

select * from t1 where  exists (select 1 from t2 where t1.name = t2.name);

對於 exists 來說,是先查詢遍歷外表 t1 ,然后每次遍歷時,再檢查在內表是否符合匹配條件,即檢查是否存在 name 相等的數據。

for(x in A){
  if(exists condition is true){result.add();}
}

 

 

說明:文章部分內容借鑒網上文章,部分來源於工作經驗,如有侵權,請及時聯系我進行刪除。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM