2013-04-11 112 views
0

我遇到了以下查詢的性能問題,我想獲取有關銷售線和每條銷售線的一些信息我想查明庫存中收到的最後一個日期:查詢子查詢執行可怕

SELECT  XAL_SUPERVISOR.SALESTABLE.SALESNUMBER, XAL_SUPERVISOR.SALESTABLE.DEBTORACCOUNT, XAL_SUPERVISOR.SALESTABLE.DELIVERYNAME, 
        XAL_SUPERVISOR.SALESTABLE.DELIVERYADDRESS3, XAL_SUPERVISOR.SALESTABLE.REQUISNUMBER, XAL_SUPERVISOR.SALESTABLE.CUSTOMERREF, 
        XAL_SUPERVISOR.SALESTABLE.ROUTE, XAL_SUPERVISOR.SALESTABLE.ROUTENUMBER, XAL_SUPERVISOR.SALESTABLE.CMPVWSTATUS, 
        XAL_SUPERVISOR.SALESTABLE.CMPLOGISTIEK, XAL_SUPERVISOR.SALESTABLE.USVEHICLE, XAL_SUPERVISOR.SALESTABLE.ELCSALSTCALL, 
        XAL_SUPERVISOR.SALESTABLE.ELCSALSTOK, XAL_SUPERVISOR.SALESTABLE.ELCEDICODE, XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER, 
        XAL_SUPERVISOR.STOCKTABLE.ITEMNAME, XAL_SUPERVISOR.SALESTRANS.QTYORDERED, XAL_SUPERVISOR.SALESTRANS.STOCKLOC AS REGELLOC, 
        XAL_SUPERVISOR.STOCKTABLE.STOCKLOC AS STDLOC, XAL_SUPERVISOR.SALESTABLE.DELIVERYDATE, XAL_SUPERVISOR.SALESTABLE.DATASET, 
        XAL_SUPERVISOR.SALESTABLE.CMPCORRECTIE, XAL_SUPERVISOR.SALESTRANS.ELCORGQTYORDERED AS ORG_BESTELD, 
        XAL_SUPERVISOR.STOCKTABLE.CMPVERVALLEN, 
         (SELECT  (SUM(STS.ENTEREDQTY) + SUM(STS.RECEIVED) - SUM(STS.DRAWN)) 
          FROM   XAL_SUPERVISOR.STOCKSUM STS 
          WHERE  STS.ITEMNUMBER = XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER AND STS.DATASET = 'CMP' 
          GROUP BY STS.ITEMNUMBER) AS VOORRAAD, 
         (SELECT  SUM(STS.ORDERED) 
          FROM   XAL_SUPERVISOR.STOCKSUM STS 
          WHERE  STS.ITEMNUMBER = XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER AND STS.DATASET = 'CMP' 
          GROUP BY STS.ITEMNUMBER) AS BESTELD, 
         (SELECT  SUM(STS.RESERVPHYSICAL) 
          FROM   XAL_SUPERVISOR.STOCKSUM STS 
          WHERE  STS.ITEMNUMBER = XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER AND STS.DATASET = 'CMP' 
          GROUP BY STS.ITEMNUMBER) AS GERESERVEERD, 
         (SELECT  DDT.QTY 
          FROM   XAL_SUPERVISOR.DEBDLVTRANS DDT 
          WHERE  DDT.TRANSID = XAL_SUPERVISOR.SALESTRANS.TRANSID AND DDT.DATASET = 'CMP') AS PAKBONAANTAL, 
         (SELECT  DIT.QTY 
          FROM   XAL_SUPERVISOR.DEBINVTRANS DIT 
          WHERE  DIT.TRANSID = XAL_SUPERVISOR.SALESTRANS.TRANSID AND DIT.DATASET = 'CMP') AS FACTUURAANTAL, 
         (SELECT  MAX(ST.DATEPHYSICAL) 
          FROM   XAL_SUPERVISOR.STOCKTRANS ST 
          WHERE  ST.ITEMNUMBER = XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER AND ST.DATASET = 'CMP' AND ST.StatusInFlow < 3 AND ST.DCType = 2) 
        AS LTSTGELEVERD 
FROM   XAL_SUPERVISOR.SALESTABLE, XAL_SUPERVISOR.SALESTRANS, XAL_SUPERVISOR.STOCKTABLE 
WHERE  XAL_SUPERVISOR.SALESTABLE.DATASET = XAL_SUPERVISOR.SALESTRANS.DATASET AND 
        XAL_SUPERVISOR.SALESTABLE.SALESNUMBER = XAL_SUPERVISOR.SALESTRANS.SALESNUMBER AND 
        XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER = XAL_SUPERVISOR.STOCKTABLE.ITEMNUMBER AND 
        XAL_SUPERVISOR.SALESTRANS.DATASET = XAL_SUPERVISOR.STOCKTABLE.DATASET AND (XAL_SUPERVISOR.SALESTABLE.DELIVERYDATE = :Leverdatum) AND 
        (XAL_SUPERVISOR.SALESTABLE.DATASET = 'CMP') AND (XAL_SUPERVISOR.SALESTABLE.CMPCORRECTIE = 0) 

這部分減緩下來(沒有它,它在<運行10秒鐘):

(SELECT  MAX(ST.DATEPHYSICAL) 
          FROM   XAL_SUPERVISOR.STOCKTRANS ST 
          WHERE  ST.ITEMNUMBER = XAL_SUPERVISOR.SALESTRANS.ITEMNUMBER AND ST.DATASET = 'CMP' AND ST.StatusInFlow < 3 AND ST.DCType = 2) 
        AS LTSTGELEVERD 

當我運行在SQL再加上我看到它取主查詢,然後停頓了很長一段時間獲取上述子查詢?

+1

檢查你的表'STOCKTRANS'是否被正確索引 – 2013-04-11 15:46:35

+1

有些顧問通過調整其他人的shonky代碼來做出非常好的生活。如果僅僅是簡單地看待一個查詢並且說「在那裏改變那條線」,他們不能收取太多的費用。有很多因素可能會導致糟糕的表現。數據量,數據傾斜,磁盤損壞,內存不足,內存不足,失效統計信息,缺少索引,索引錯誤,磁盤排序。寫得不好的SQL只是其中的一件事情。 – APC 2013-04-11 15:54:27

+1

正如@Majid所說:檢查是否有正確的索引以及查詢計劃是否實際使用它們。 – mzedeler 2013-04-11 18:15:36

回答

1

有一對夫婦的事情,你可以嘗試:

  • 第四和第五子查詢只是得到一個標值,這樣他們就可以被放入查詢的主體。看起來你在這裏使用子查詢來避免LEFT JOIN

  • 第一,第二,第三和第六子查詢可以使用公用表表達式(CTE)組合,也稱爲Oracle WITH子句。與其他子查詢值一樣,現在必須使用LEFT JOIN來合併這些值。

此外,如果使用ANSI連接語法,則會更容易。這裏的答案(但請注意我留下了很多的「旁觀者」列,因此會有些小巧的;您可以在如果這個解決方案適用於您添加這些回):

WITH StkSum AS (
    SELECT 
    STS.ITEMNUMBER, 
    SUM(STS.ENTEREDQTY) + SUM(STS.RECEIVED) - SUM(STS.DRAWN) AS VOORRAAD, 
    SUM(STS.ORDERED) AS BESTELD, 
    SUM(STS.RESERVPHYSICAL) AS GERESERVEERD, 
    MAX(ST.DATEPHYSICAL) AS LTSTGELEVERD 
    FROM XAL_SUPERVISOR.STOCKSUM STS 
    INNER JOIN XAL_SUPERVISOR.STOCKTRANS ST ON STS.ITEMNUMBER = ST.ITEMNUMBER 
    WHERE STS.DATASET = 'CMP' 
    AND ST.DATASET = 'CMP' 
    AND ST.StatusInFlow < 3 
    AND ST.DCType = 2 
) 
SELECT 
    XAL_SUPERVISOR.SALESTABLE.SALESNUMBER, 
    ... all those SALESTABLE and SALESTRANS and STOCKTABLE columns ..., 
    StkSum.VOORRAAD, 
    StkSum.BESTELD, 
    StkSum.GERESERVEERD, 
    NVL(XAL_SUPERVISOR.DEBDLVTRANS.QTY, 0) AS PAKBONAANTAL, 
    NVL(XAL_SUPERVISOR.DEBINVTRANS.QTY, 0) AS FACTUURAANTAL, 
    StkSum.LTSTGELEVERD 
FROM XAL_SUPERVISOR.SALESTABLE 
INNER JOIN XAL_SUPERVISOR.SALESTRANS ON 
    SalesTable.DataSet = SalesTrans.DataSet AND 
    SalesTable.SalesNumber = SalesTrans.SalesNumber 
INNER JOIN XAL_SUPERVISOR.STOCKTABLE ON 
    SalesTrans.ItemNumber = StockTable.ItemNumber AND 
    SalesTrans.DataSet = StockTable.DataSet 
LEFT OUTER JOIN StkSum ON StkSum.ITEMNUMBER = SalesTrans.ITEMNUMBER 
LEFT OUTER JOIN XAL_SUPERVISOR.DEBDLVTRANS DDT ON DDT.TRANSID = SalesTrans.TRANSID 
LEFT OUTER JOIN XAL_SUPERVISOR.DEBINVTRANS DIT ON DIT.TRANSID = SalesTrans.TRANSID 
WHERE 
    (XAL_SUPERVISOR.SALESTABLE.DELIVERYDATE = :Leverdatum) AND 
    (XAL_SUPERVISOR.SALESTABLE.DATASET = 'CMP') AND 
    (XAL_SUPERVISOR.SALESTABLE.CMPCORRECTIE = 0) AND 
    DDT.DATASET = 'CMP' AND 
    DIT.DATASET = 'CMP' 

最後,請注意由於表和列和條件的絕對數量,如果上面的查詢是100%正確,我會感到震驚。我盡力了,但是我的最佳效果可能不夠好:) Tweakage可能是需要的。

+0

感謝您的幫助Ed!問候邁克 – 2013-04-12 07:33:58

1

如果您正在從.net或coldfusion等應用程序運行此查詢,則可以單獨運行查詢並將它們加入到應用程序中。使用.net它將是DataTable的linq,而coldfusion則是查詢的查詢。

你可以在存儲過程中做同樣的事情。用子查詢中的數據填充臨時表並改爲加入臨時表。

雖然這些事情是違反直覺的,甚至可能代表最差的做法,但它們有時適合當前的情況。

1

SELECT子句中的子查詢往往表現不佳一種改進方法是使用內聯視圖或WITH子句來計算每個ITEMNUMBER的最大值,然後加入它。

WITH datephysical_max as 
    (SELECT Max(ST.datephysical) max_ , ST.itemnumber 
     FROM xal_supervisor.stocktrans ST 
     WHERE 
       AND ST.dataset = 'CMP' 
       AND ST.statusinflow < 3 
       AND ST.dctype = 2 
     GROUP BY) 
SELECT 
     ...., 
     st.LTSTGELEVERD 
FROM xal_supervisor.salestable 
     inner join xal_supervisor.salestrans 
       ON xal_supervisor.salestable.dataset = 
        xal_supervisor.salestrans.dataset 
        AND xal_supervisor.salestable.salesnumber = 
         xal_supervisor.salestrans.salesnumber 
        AND xal_supervisor.salestrans.itemnumber = 
         xal_supervisor.stocktable.itemnumber 
     inner join xal_supervisor.stocktable 
       ON xal_supervisor.salestrans.dataset = 
        xal_supervisor.stocktable.dataset 
     INNER JOIN datephysical_max st 
       ON ST.itemnumber = xal_supervisor.salestrans.itemnumber 
WHERE (xal_supervisor.salestable.deliverydate = :Leverdatum) 
     AND (xal_supervisor.salestable.dataset = 'CMP') 
     AND (xal_supervisor.salestable.cmpcorrectie = 0) 
+0

感謝您的幫助康萊德! – 2013-04-12 07:34:44

1

你的選擇會減慢查詢有以下東西使它緩慢:

  1. 數學(不到)可以區分索引不被使用。考慮
    更改爲在列表中,如果列表是小

  2. 如果沒有索引如下這將是緩慢的

    一個上(ST.item_number,ST.dataset,ST.status_in_flow,ST .dctype) one on XAL_SUPERVISOR(itemNumber) one on datephysical可以被max使用,因爲它會導致order by。

  3. 考慮首先運行查詢所有where子句,然後根據它做max。

如果不使用索引有很多原因。在where子句中的數學,如果大rowcount然後明確考慮項目1,所以索引將被使用。另外,如果列可以爲null,to_upper等,你可以使用基於函數的索引。