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 で実行すると、メイン クエリがフェッチされ、上記のサブクエリをフェッチするために長時間一時停止することがわかります。

4

4 に答える 4

1

SELECT 句のサブクエリはパフォーマンスが低下する傾向があります。これを改善する 1 つの方法は、インライン ビューまたは 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

あなたが試すことができるいくつかのことがあります:

  • 4 番目と 5 番目のサブクエリはスカラー値を取得するだけなので、クエリの本体に入れることができます。を避けるために、ここでサブクエリを使用しているようですLEFT JOIN

  • 1 番目、2 番目、3 番目、および 6 番目のサブクエリは、共通テーブル式 (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

クエリを遅くする選択には、次のことがあり、遅くなります。

  1. math (より小さい) は、インデックスを使用しない場合があります。
    リストが小さい場合は、リスト内に変更することを検討してください

  2. 次のようなインデックスがない場合、遅くなります

    (ST.item_number, ST.dataset, ST.status_in_flow, ST.dctype) に 1 つ XAL_SUPERVISOR(itemNumber) に 1 つ datephysical に 1 つを使用すると、オーダー バイが発生するため、max で使用できます。

  3. 最初にすべての where 句に対してクエリを実行してから、それに基づいて max を実行することを検討してください。

インデックスが使用されない場合、多くの理由があります。where句の数学、行数が多い場合、アイテム1を明確に考慮するため、インデックスが使用されます。また、列がヌル、to_upper などになる可能性がある場合は、関数ベースのインデックスを使用できます。

于 2013-04-12T12:30:56.593 に答える
1

このクエリを .net や coldfusion などのアプリケーションから実行している場合は、クエリを個別に実行してアプリケーションに結合できます。.net では linq to DataTable になり、coldfusion ではクエリ オブ クエリになります。

ストアド プロシージャでも同じようなことができます。サブクエリからのデータを一時テーブルに入力し、代わりに一時テーブルに結合します。

この種のことは直感に反しており、最悪の慣行を表している可能性さえありますが、目の前の状況に適している場合もあります。

于 2013-04-11T16:23:01.367 に答える