雖然你這列上建了索引,查詢條件也是索引列,但最終執行計畫沒有走它的索引。下面是引起這種問題的幾個關鍵點。
某個表中,有兩列(id和c_id)都建了單獨索引,下面這種查詢條件不會走索引
select
*from test where id=c_id;
這種情況會被認為還不如走全表掃瞄。
我們在設計資料庫表時,應該盡力避免null值出現,如果非要不可避免的要出現null值,也要給乙個default值,數值型可以給0、-1之類的, 字串有時候給空串有問題,就給乙個空格或其他。如果索引列是可空的,是不會給其建索引的,索引值是少於表的count(*)值的,所以這種情況下,執行計畫自然就去掃瞄全表了。
select
*from test where id is
notnull
;
我們知道建立索引時,給每乙個索引列建立乙個條目,如果查詢條件為等值或範圍查詢時,索引可以根據查詢條件去找對應的條目。反過來當查詢條件為非時,索引定位就困難了,執行計畫此時可能更傾向於全表掃瞄,這類的查詢條件有:<>、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
notin(6
,7,8
,9,0
);select
*from test where
notexists
(select
1from test_02 where test_02.id=test.id)
;
select
*from test where name like 張||
'%';
查詢條件上盡量不要對索引列使用函式,比如下面這個sql
select
*from test where upper(name)
='sunyang'
;
這樣是不會走索引的,因為索引在建立時會和計算後可能不同,無法定位到索引。但如果查詢條件不是對索引列進行計算,那麼依然可以走索引。比如
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;
就可以使用索引了。
先說明一下,虛擬索引的建立是否有用,需要看具體的執行計畫,如果起作用就可以建乙個,如果不起作用就算了。
普通索引這麼建:
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 in1.
.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是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
;
MySQL索引分類 何時情況下使用 何時失效
目錄分類 何時使用 何時不使用索引 何時失效 explain語句 mysql索引分為普通索引 唯一索引 主鍵索引 組合索引 全文索引。索引不會包含有null值的列,索引項可以為null 唯一索引 組合索引等 但是只要列中有null值就不會被包含在索引中。普通索引 create index index...
索引失效的情況
索引並不是時時都會生效的,比如以下幾種情況,將導致索引失效 如果條件中有or,即使其中有條件帶索引也不會使用 這也是為什麼盡量少用or的原因 注意 要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引 對於多列索引,不是使用的第一部分,則不會使用索引 like查詢是以 開頭 如果列型別是...
索引失效的情況
對於後端開發工程師來說,熟練掌握資料庫的極有必要的,靈活使用索引也是必須技能。但索引並不是時時都會生效的,以下列舉出索引失效的原因 對索引列進行運算導致索引失效,運算包括 等 使用oracle內部函式導致索引失效.對於這樣情況應當建立基於函式的索引.單獨的 like 百分號在前.單獨引用復合索引裡非...