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 plus 中运行它时,我看到它获取主查询然后暂停很长时间以获取上述子查询?

4

4 回答 4

1

您的选择会减慢查询速度,这会导致查询速度变慢:

  1. 数学(小于)可以不使用大小写索引。
    如果列表很小,请考虑更改为 in 列表

  2. 如果您没有如下索引,它会很慢

    (ST.item_number, ST.dataset, ST.status_in_flow, ST.dctype) 上的一个 XAL_SUPERVISOR(itemNumber) 上的一个 datephysical 上的一个可以由 max 使用,因为它会导致 order by。

  3. 考虑首先对所有 where 子句运行查询,然后基于它执行 max 。

如果不使用索引,则有很多原因。where 子句中的数学,如果行数很大,那么肯定会考虑第 1 项,因此将使用索引。此外,如果 column 可以为 null、to_upper 等,您可以使用基于函数的索引。

于 2013-04-12T12:30:56.593 回答
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 ) 
于 2013-04-11T17:05:40.950 回答
1

您可以尝试以下几件事:

  • 第四个和第五个子查询只是得到一个标量值,因此可以放入查询的主体。看起来您在这里使用子查询来避免LEFT JOIN.

  • 第一个、第二个、第三个和第六个子查询可以使用公用表表达式 (CTE) 组合,也称为 OracleWITH子句。与其他子查询值一样,现在必须使用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% 正确的,我会感到震惊。我尽了最大努力,但我的最好在这里可能还不够好:) 可能需要调整。

于 2013-04-11T17:06:10.300 回答
1

如果您从 .net 或 Coldfusion 等应用程序运行此查询,则可以单独运行查询并将它们加入应用程序。使用.net,它将是 linq 到 DataTable,而coldfusion 将是查询的查询。

您可以在存储过程中做同样的事情。使用来自子查询的数据填充临时表并改为连接到临时表。

虽然这类事情是违反直觉的,甚至可能代表最糟糕的做法,但有时它们适合手头的情况。

于 2013-04-11T16:23:01.367 回答