您好,登錄后才能下訂單哦!
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');
此處是走索引的,符合預期;
場景二:
select * from TEST_INDEX_DEMO T WHERE
T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792') AND T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9');
此處可以看到ORACLE的優化器實際上把查詢條件的順序進行了調整,所以同樣走了索引,符合預期;
場景三:
select * from TEST_INDEX_DEMO T WHERE
T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9');
此處因為查詢條件為復合索引的前導列,所以走了索引,符合預期;
場景四:
select * from TEST_INDEX_DEMO T WHERE
T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
此處沒有走索引,走的全表掃描,我原本以為即便不是復合索引的前導列,也會走索引的,看來我原來的認識是錯誤的。
針
對這個我特意臨時添加了index(B、A)驗證了一下,是因為查詢條件字段不是復合索引前導列導致,還是因為出于其它方面的成本考慮,測試發現,添加了
index(B、A)順序的索引后,該SQL就可以走索引了,所以應該可以認為是查詢條件字段不是復合索引前導列導致的。
場景五:
select * from TEST_INDEX_DEMO T WHERE
T.RECID=HEXTORAW('01540ED5DA7069465FB7E42D07EDC156') AND T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9');
ORACLE優化器并沒有調整查詢條件字段的順序,但是依然走了索引。走索引是符合預期的,但是我原本以后應該會改變字段順序的,這塊我有點不太理解,如果有看到這篇日志的大牛請幫忙解惑一下,謝謝。
場景六:
select * from TEST_INDEX_DEMO T WHERE
T.RECID=HEXTORAW('01540ED5DA7A69461D878CAE1CED2B7E') AND T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
此處沒有走索引,倒是符合預期,汗~~~~
場景七:
select * from TEST_INDEX_DEMO T WHERE
T.RECID=HEXTORAW('01540ED5DA7A69461D878CAE1CED2B7E') AND T.CUSTOMER_ID=HEXTORAW('01540EAA1D8E690099261D41257815D9') AND
T.PRODUCT_ID=HEXTORAW('01540EAB83EC6900E30EAD424661D792');
此處走索引了,結果倒是符合預期。
----------------------------------------------------
結果對比及結論:
所以經此對比,我的結論是:
1、查詢條件字段與復合索引字段一致的,無論順序如何,ORACLE優化器會自動調整順序,結論是會走索引;
2、查詢條件字段與復合索引字段不一致,查詢條件字段包含復合索引前導列的,可以走索引;不包含索引前導列,則不走索引;
--------------------------
所以,由此結論可以看出,在設計查詢的時候,還是應該要求開發在組織SQL的時候對于第一個查詢條件該用哪個字段還是需要綜合考慮系統所有查詢來進行設計一下的。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。