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();}
}
說明:文章部分內容借鑒網上文章,部分來源於工作經驗,如有侵權,請及時聯系我進行刪除。