2012-04-04 36 views
3

正如你可以看到Oracle可以利用兩個索引並解決整個查詢而無需通過rowid訪問表?Oracle:利用使用兩個索引

SELECT 'Scarti letture GAS' tipo, campo47 pdf, COUNT (1) n 
    FROM out.CONSUMI_GEE_LC_T500_00 v 
    WHERE stato = 'SC' 
    AND stato is not null 
    AND campo47 is not null 
    GROUP BY 'Scarti letture GAS', campo47; 

我已經做了一個測試,添加字段campo47到STATO索引。性能從1'49''增加到0,6s。

有關stato的索引不具有選擇性。 campo47上的索引(意思是field47)真的很有選擇性。

enter image description here

enter image description here

enter image description here

回答

7

你說CAMPO47是高度選擇性的。但是你只是過濾IS NOT NULL。因此,它具有多少不同的值並不重要,優化器不會將其用作入口點。

它有多麼有選擇性?從解釋計劃中的基數可以看出,選擇STATO ='SC'會在表中找到12856行。這些行中的12702明顯具有CAMPO47值,因此只有154行被無效性測試過濾掉。如果優化器在CAMPO47上索引了多少行會返回?可能還有更多。

優化器只能使用一個堆索引來訪問表上的行。 (當應用星形轉換時,位圖索引的機制是不同的)。所以,如果你認爲額外的表訪問是一個難以承受的負擔,那麼你有一個選擇:複合指數。如果STATO是真正的非選擇性的(相對較少的行),那麼您可以安全地用一個替換現有的索引(STATO,CAMPO47)。


有一個老把戲輕推到數據庫使用索引來訪問IS NOT NULL操作,那就是使用一個操作數,其中列包含的值只能是真。舉例來說,像這樣的字符串列(我假設一些所謂CAMPO47只是長谷是一個字符串):

AND campo47 >= chr(0) 

,將匹配包含一個或多個ASCII字符的任意列。不確定它是否會導致你描述的「雙指數」優化,但它是值得一試的。 (我會自己測試一下,但是我現在沒有訪問Oracle數據庫的機會,而當我試圖查看解釋計劃時,SQL小提琴投擲了)

+0

我該如何測試插入/選擇性能指數?即用(STATO,CAMPO47)替代STATO上的指數,或者刪除STATO和Campo47上的指數,並將它們替換爲只有一個指數(STATO,CAMPO47)。 – Revious 2012-04-04 09:19:26

+0

我認爲Oracle應該通過訪問所有rowid與stato ='SC',然後快速完整地索引掃描campo47上的索引並通過rowid進行搜索,並直接返回resutl而不訪問表。 – Revious 2012-04-04 09:22:52

+0

@APC你可以給我發一封電子郵件'管理員在sqlfiddle點com'或只是鏈接它在這裏,你遇到的執行計劃sqlfiddle發現問題的一個例子?謝謝 – 2012-04-04 17:14:13