複合索引使用的先決條件

PS:懶得重新編輯圖片了,直接把我從51上的日誌拷過來了。


背景:

今天,接到一個項目的項目經理電話,告之說生產環境有幾個查詢超級慢,就是查詢單張表的數據,查詢條件也很簡單,但是加了索引以後並沒有走索引,依然還是走的全表掃描。
聽到該問題描述,我開始浮想聯翩,統計信息太舊?存在隱式轉換?索引樹傾斜度太高,導致oracle認爲走索引的成本更高?
帶着各種可能的原因猜想,火速趕到了現場,發現原來都是我想多了。不走索引單純是建立的索引不合理,查詢條件是多個字段,應該建立複合索引,現場維護人員只對其中單個字段建立了索引,ORACLE認爲不如走全表掃描開銷小,所以沒走索引。
汗~~~~~~
添加索引的時候發現,幾個不同的查詢,查詢條件字段都一樣,但是寫的順序卻不一樣(開發寫SQL太隨意了!!!!字段一樣,順序也寫成一樣啊!!!!!!!),結果先劇透一下,同樣也是可以走索引的。而由此聯想到些問題,於是在解決完效率問題後,在個人環境上做了一個驗證。
這個就是完整的背景。

---------------------------------------------------
驗證內容:
ORACLE 11GR2 複合索引的使用條件。
前提條件:
創建一張表,並對字段A、B建立組合索引,順序爲index(A、B);
測試場景:
針對以下6個場景進行測試:
1、查詢條件爲:A='XXX' and B='YYY';  順序完全一致的情況;
2、查詢條件爲:B='YYY' and A='XXX';  順序不一致的情況;
3、查詢條件爲:A='XXX';              單個字段且爲複合索引前導列的情況;
4、查詢條件爲:B='YYY';              單個字段且不是複合索引前導列的情況;
5、查詢條件爲:C='ZZZ' and A='XXX';  查詢條件既包含其它字段,也包含複合索引前導列的情況;
6、查詢條件爲:C='ZZZ' and B='YYY';  查詢條件既包含其它字段,也包含複合索引非前導列字段的情況;
7、查詢條件爲:C='ZZZ' and A='XXX' and B='YYY';  查詢條件除複覈索引字段外還包括其它字段,且索引外字段在第一位;

---------------------------------------------------
執行過程:

創建測試數據:

create table test_index_demo(recid  RAW(16) not null,customer_id RAW(16) not null,product_id  RAW(16) not null)
create unique index index_test on test_index_demo (CUSTOMER_ID, PRODUCT_ID)
根據查詢字段做笛卡爾積準備了將近3000萬數據;
exec dbms_stats.gather_index_stats(ownname => 'gboss',indname =>'test_index_demo');

分別針對每個場景進行測試,查看執行計劃如下:
場景一:
select * from TEST_INDEX_DEMO T WHERE T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9') AND T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
15146915_201605031546181Jpj4.jpg
此處是走索引的,符合預期;

場景二:
select * from TEST_INDEX_DEMO T WHERE T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792') AND T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9');
15146915_201605031556321uquv.jpg
此處可以看到ORACLE的優化器實際上把查詢條件的順序進行了調整,所以同樣走了索引,符合預期;

場景三:
select * from TEST_INDEX_DEMO T WHERE T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9');
15146915_201605031558281i7u3.jpg
此處因爲查詢條件爲複合索引的前導列,所以走了索引,符合預期;

場景四:
select * from TEST_INDEX_DEMO T WHERE T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
15146915_201605031601111QB1j.jpg
此處沒有走索引,走的全表掃描,我原本以爲即便不是複合索引的前導列,也會走索引的,看來我原來的認識是錯誤的。
針 對這個我特意臨時添加了index(B、A)驗證了一下,是因爲查詢條件字段不是複合索引前導列導致,還是因爲出於其它方面的成本考慮,測試發現,添加了 index(B、A)順序的索引後,該SQL就可以走索引了,所以應該可以認爲是查詢條件字段不是複合索引前導列導致的。

場景五:
select * from TEST_INDEX_DEMO T WHERE
T.RECID=HEXTORAW('01540ED5DA7069465FB7E42D07EDC156') AND T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9');
15146915_201605031610021VoXA.jpg
ORACLE優化器並沒有調整查詢條件字段的順序,但是依然走了索引。走索引是符合預期的,但是我原本以後應該會改變字段順序的,這塊我有點不太理解,如果有看到這篇日誌的大牛請幫忙解惑一下,謝謝。

場景六:
select * from TEST_INDEX_DEMO T WHERE
T.RECID=HEXTORAW('01540ED5DA7A69461D878CAE1CED2B7E') AND T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
15146915_201605031621211duiD.jpg
此處沒有走索引,倒是符合預期,汗~~~~

場景七:
select * from TEST_INDEX_DEMO T WHERE
T.RECID=HEXTORAW('01540ED5DA7A69461D878CAE1CED2B7E') AND T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9') AND T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
15146915_201605031630321dhNM.jpg
此處走索引了,結果倒是符合預期。

----------------------------------------------------
結果對比及結論:


所以經此對比,我的結論是:
1、查詢條件字段與複合索引字段一致的,無論順序如何,ORACLE優化器會自動調整順序,結論是會走索引;
2、查詢條件字段與複合索引字段不一致,查詢條件字段包含複合索引前導列的,可以走索引;不包含索引前導列,則不走索引;
--------------------------
所以,由此結論可以看出,在設計查詢的時候,還是應該要求開發在組織SQL的時候對於第一個查詢條件該用哪個字段還是需要綜合考慮系統所有查詢來進行設計一下的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章