2013-04-11 100 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等,你可以使用基于函数的索引。