2010-12-02 62 views
0

我有一個查詢其需要5鉅額表數據,可以請你幫我這個查詢的性能優化:幫助SQL調優 - ORACLE

SELECT DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1, 
     t1.element_id, 
     t1.start_date , 
     t1.amount, 
     NVL(t5.abrev, NULL) AS criteria, 
     t1.case_id , 
     NVL(t5.value, NULL) segment, 
     add_months(t1.start_date, -1) invoice_date, 
     NVL((SELECT SUM(b.amount) 
      FROM TABLE1 a, TABLE3 b 
      WHERE a.element_id = b.element_id 
       AND b.date_invoicing < a.start_date 
       AND t1.element_id = a.element_id), 
      0) amount_2 
    FROM TABLE1 t1, TABLE2 t2, TABLE3 t3, TABLE4 t4, TABLE5 t5 
WHERE t1.TYPE = 'INVOICE' 
    AND t2.case_id = t3.case_id 
    AND t2.invoicing_id = t3.invoicing_id 
    AND t2.date_unpaid IS NULL 
    AND t1.element_id = t3.element_id(+) 
    AND add_months(t1.start_date, -1) < 
     NVL(t4.DT_FIN_DT(+), SYSDATE) 
    AND add_months(t1.start_date, -1) >= t4.date_creation(+) 
    AND t1.case_id = t4.case_id(+) 
    AND t4.segment = t5.abrev(+) 
    AND t5.Type(+) = 'CRITERIA_TYPE'; 

是有什麼錯誤的,可以用什麼來代替其他?
感謝您的幫助

+2

現在你已經嘗試使用(+)外連接到t3,通過其他不使用(+)的謂詞強制回到內連接,如「t2.case_id = t3.case_id」。如果你可以使用ANSI連接編寫它,它將不太容易出錯並且易於閱讀。儘管如此,這與性能無關。 – 2010-12-02 14:16:25

回答

1

正如其他人所指出的,很難說不看執行計劃。

但是......有些事情我會與有關:如@TonyAndrews在他的評論中提及了上述

  1. 的外連接表3在主查詢是不完整的。請參閱Common errors seen when using OUTER-JOIN上的「不完整聯結跟蹤」示例。 這意味着您的查詢可能產生了錯誤的結果,但是如果不知道查詢和模式的完整意圖,除了您可以確定地知道這一點外,沒有人會這樣做。

    更新您的查詢以使用Oracle風格TableName.ColumnName(+)中的ANSI風格INNER/[LEFT|RIGHT] OUTER語法將有助於使這一點更加明顯。

  2. 標量子查詢將得到運行的每一行,可能會很慢(假設TABLE3很大)。

    NVL((SELECT SUM(b.amount) 
        FROM TABLE1 a, TABLE3 b 
        WHERE a.element_id = b.element_id 
         AND b.date_invoicing < a.start_date 
         AND t1.element_id = a.element_id), 
        0) amount_2 
    

    因此,我沒有看到有必要在這個子查詢又包括表1:如果有不TABLE3.element_idTABLE3.date_invoicing有用的索引這將是極其緩慢。這可能是更好的重構爲這樣:

    NVL((SELECT SUM(b.amount) 
        FROM TABLE3 b 
        WHERE t1.element_id = b.element_id 
         AND b.date_invoicing < t1.start_date, 
        0) amount_2 
    

    或者,你甚至可能會更好重構這個使用分析功能(SO questionOracle documentation)如果爲b.amount值相加的標準是相同的,包括他們在查詢擺在首位:

    SUM(b.amount) OVER (PARTITION BY b.element_id) amount_2 
    

    顯然,你現在有不同的標準來總結b.amount,因爲你在主要查詢和子查詢中以不同的方式加入到TABLE3中,但我想象這更像是「不完整的加入路徑」的一個因素,而不是有目的的設計(我的猜測,因爲我不能從代碼本身講出查詢的意圖)。

2

您必須做的第一件事是使用顯式聯接。這會將您的連接與您的過濾器分開,並幫助您更好地調整此過濾器。

請檢查這些連接是否正確。

SELECT 
    DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1, 
    t1.element_id, 
    t1.start_date , 
    t1.amount, 
    NVL(t5.abrev, NULL) AS criteria, 
    t1.case_id , 
    NVL(t5.value, NULL) segment, 
    add_months(t1.start_date, -1) invoice_date, 
    NVL 
    (
     (SELECT SUM(b.amount) 
     FROM TABLE1 a, TABLE3 b 
     WHERE a.element_id = b.element_id 
     AND b.date_invoicing < a.start_date 
     AND t1.element_id = a.element_id), 
    0) amount_2 
FROM 
    TABLE1 t1 

    LEFT OUTER JOIN TABLE3 t3 
     on t1.element_id = t3.element_id 

    INNER JOIN TABLE2 t2, 
     on t2.invoicing_id = t3.invoicing_id 
     and t2.case_id = t3.case_id 

    LEFT OUTER JOIN TABLE4 t4 
     on t1.case_id = t4.case_id 

    LEFT OUTER JOIN TABLE5 t5 
     on t4.segment = t5.abrev 

WHERE t1.TYPE = 'INVOICE' 
    AND t2.date_unpaid IS NULL 
    AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE) 
    AND add_months(t1.start_date, -1) >= t4.date_creation(+) 
    AND t5.Type(+) = 'CRITERIA_TYPE'; 

如果是,那麼你可以做幾件事情,但最好的辦法是看執行計劃。

+0

它會提高性能還是提高可讀性? – mcha 2010-12-02 14:14:50

+2

在性能方面,它們應該完全一樣。分離可以幫助您識別要調整得更好的東西。 – 2010-12-02 14:22:27

1

優化程序可能產生了不理想的執行計劃。或者考慮到數據庫實際需要完成的工作量,它可能會盡可能快地運行。 沒有解釋計劃,知道鍵,關係和索引,有點難以分辨發生了什麼。

選擇列表中的標量子查詢是通常當外部查詢返回大量行時,不是一個好主意。

由於函數調用,以下表達式可能會阻止優化器使用統計信息。索引可能不會用於出於同樣的原因。

AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE) 
AND add_months(t1.start_date, -1) >= t4.date_creation(+) 

真的不能比這更具體的:)

0

這是升技奇怪在這裏,當你窩Select語句內的另一個

NVL((SELECT SUM(b.amount) 
      FROM TABLE1 a, TABLE3 b 
      WHERE a.element_id = b.element_id 
       AND b.date_invoicing < a.start_date 
       AND t1.element_id = a.element_id), 
      0) amount_2 

你需要爲表寫一遍後「從」加入。