2012-03-27 181 views
0

我在Oracle 11g中編寫了以下SQL查詢。如何減少Oracle中以下查詢的執行時間?

SELECT p.matchcode  pmatchcode, 
     p1.matchcode  p1matchcode, 
     p.digits   digit, 
     p1.effectivedate peff, 
     p1.expirydate pexp, 
     p.expirydate  p1exp, 
     p.tariff_id  tariff_id 
    FROM tt_matchcodes_view p1 
    JOIN tt_matchcodes_view p 
    on p.tariff_id = p1.tariff_id 
    AND p.type_id = p1.type_id 
    AND p1.Digits = p.Digits 
    AND p.matchcode <> p1.matchcode 
    AND p1.EffectiveDate < p.expirydate 
    AND (p1.expirydate IS NULL OR p1.expirydate > p.expirydate) 
    AND substr(p.matchcode, 0, length(p1.matchcode)) = p1.matchcode; 

tt_matchcodes_view表有71392條記錄。我在字段matchcode and digits上的表上創建了兩個索引。執行時間超過10分鐘。無論如何減少執行時間。

樣品表中的數據:

MATCHCODE DIGITS DEST_ID MATCH EFFECTIVEDATE EXPIRYDATE INHERITED TARIFF_ID TYPE_ID 
1787 1787 73999 1 01/03/2012  0 22 1 
1787201 1787 73999 0 01/03/2012  -1 22 1 
1787202 1787 73999 0 01/03/2012  -1 22 1 
1787203 1787 73999 0 01/03/2012  -1 22 1 
1787204 1787 73999 0 01/03/2012  -1 22 1 
1787205 1787 73999 0 01/03/2012  -1 22 1 
1787206 1787 73999 0 01/03/2012  -1 22 1 
1787207 1787 73999 0 01/03/2012  -1 22 1 
1787208 1787 73999 0 01/03/2012  -1 22 1 
1787212 1787 73999 0 01/03/2012  -1 22 1 

執行計劃:

OPERATION OPTIONS OBJECT_NAME OBJECT_INSTANCE OPTIMIZER ID PARENT_ID DEPTH POSITION COST CARDINALITY BYTES CPU_COST IO_COST 
SELECT STATEMENT    ALL_ROWS 0  0 703 703 3 501 83322403 698 
HASH JOIN     1 0 1 1 703 3 501 83322403 698 
TABLE ACCESS FULL TT_MATCHCODES_VIEW 2  2 1 2 1 95 65498 5174342 22711001 94 
TABLE ACCESS FULL TT_MATCHCODES_VIEW 1  3 1 2 2 95 65498 5763824 22711001 94 

Thx提前。

+0

爲什麼你有'substr(p.matchcode,0,length(p1.matchcode))'?這是沒有意義的。同樣@GauravSoni提到,請編輯並添加執行計劃 – Sathya 2012-03-27 10:05:14

+0

您將'tt_matchcodes_view'描述爲表,但它的名稱暗示着不同的東西。那麼,它真的是一張桌子,還是它實際上是一個視圖? – APC 2012-03-27 10:13:47

+0

P1的匹配碼應出現在P匹配碼中。這就是爲什麼我在那裏保持SUBSTR。 tt_matchcodes_view只是一個臨時表,不是一個視圖[忽略名稱]。 – 2012-03-27 10:19:19

回答

1

由於這是一個全局臨時表,因此您必須填充它,然後在同一會話甚至事務中執行查詢。這讓我想知道Oracle是否在空表上收集了統計數據,但沒有反映其實際內容。您可能會在運行查詢之前嘗試收集統計信息。如果這種方法有效,並且表格的內容預計不會相差很大,那麼您可能需要固定這些統計數據,以便它們不會被替換。

但是,根據您迄今爲止提供的信息,我不確定Oracle可以提供更好的計劃。僅在matchcode上的索引對於此查詢可能不可用,因爲在謂詞中給定條件。可以使用digits上的索引,但由於您自己將表加入表中,因此在執行兩次完整掃描時可能效率較低,因爲digits上始終存在匹配項(除非它爲NULL,否則)。

我們需要知道更多關於謂詞中哪些條件過濾出最多行以提出更多建議的更多細節。假設matchcode上的不等式是主要過濾器,那麼您可能會從(digits,matchcode)上的單個索引中獲得一些好處 - 它可能會將索引與其自身結合起來,並在完成表格之前刪除大量行。

2

您的表格有超過70000行。您正在選擇所有記錄兩次並根據非等值比較行。所以基本上你會將每一行與表中的每一行進行比較。 (實際上並非全部都是這樣,因爲不是TARIFF_ID或TYPE_ID或DIGITS不匹配的那些,但看起來並不多)。這是〜490,000,000個比較。在這種情況下,十分鐘的執行時間似乎不算太糟糕。

解釋計劃顯示Oracle已經選擇了最好的計劃。所有你能做的事情就是爲Oracle提供一個更有用的索引。使用where子句中所有列的複合索引可能有所幫助。事情是這樣的:

create index super_match_idx on tt_matchcodes_view 
    (tariff_id, .type_id, digits, matchcode, expirydate, effectivedate)  

這可能給你的指標,這應該是更快的超過兩個全表掃描操作的兩個完整的快速掃描。

順便說一句,您是否在填充臨時表時排序數據?使用與索引對齊的ORDER BY可以改善聚類因子。所以你可能會得到更快的檢索,因爲所有匹配的行更可能在連續的塊中。

我通常不會建議對堆表中的行進行排序,但是因爲您已經支付了插入臨時表的開銷,所以您可能會獲得儘可能多的果汁。

哦,substr(p.matchcode, 0, length(p1.matchcode))是一個死的贈品。智能鑰匙是Teh Suck!無論如何,有沒有這種情況下,SUBSTR()調用返回一個不匹配DIGITS的值? (同樣你的樣本數據是不明確的。)如果DIGITS可以識別SUBTSR()的輸出,我建議你把最後一行丟掉。