0

職場の誰かが数年前にこの UPDATE を作成しましたが、うまくいきました。問題は、プロセスで複数回呼び出されたときにほぼ 5 時間かかることです。これは通常の UPDATE ではありません。テーブル間で 1 対 1 のレコードの一致はありません。同じテーブル内の特定のフィールドの累積 (SUM) に基づいて更新すると、この SUM は日付と別のフィールドに基づく特別な条件に制限されるため、事態はさらに複雑になります。

これは、ALL VS ALL のように、1 対 1 の一致がない (暗黙の) 内部結合のようなものだと思います。たとえば、テーブルに 7000 のレコードがある場合、これは 7000 * 7000 のレコード、つまり 5500 万以上を処理します。ここではカーソルを使用する必要がありましたが、今はもっと速度が必要であり、カーソルではそこに到達できないと思います。

私の質問は次のとおりです。これを書き直して高速化する方法はありますか?? その SUM の条件に注意してください。これは (少なくとも私にとっては) 見やすい更新ではありません。

詳細情報: CodCtaCorriente と CodCtaCorrienteMon はこのテーブルの主キーですが、前に述べたように、ここで 1 対 1 の一致を作成する意図はないため、このキーはクエリで使用されません。CodCtaCorrienteMon は条件で使用されますが、条件としては使用されません。参加条件(ON)。

UPDATE #POS SET SaldoDespuesEvento = 
     (SELECT SUM(Importe) 
        FROM #POS CTACTE2
       WHERE CTACTE2.CodComitente = #POS.CodComitente  
         AND CTACTE2.CodMoneda = #POS.CodMoneda
         AND CTACTE2.EstaAnulado = 0 
         AND (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) > 0 
              OR
             (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) = 0 
              AND (#POS.CodCtaCorrienteMon >= CTACTE2.CodCtaCorrienteMon)))) 
WHERE #POS.EstaAnulado = 0 AND #POS.EsSaldoAnterior = 0

スクリーンショット - 実行計画

4

3 に答える 3

1

クエリ プランからは、インデックス スプールの直後のフィルターでほとんどの時間を費やしているように見えます。

このクエリを数回実行する場合は、「CodComitente」、「CodMoneda」、「EstaAnulado」、「FechaLiquidacion」、および「CodCtaCorrienteMon」列にインデックスを作成します。

Index Spool イテレータについてはよく知りません。しかし、基本的に私が理解していることから、クエリ時に作成される「一時的な」インデックスとして使用されます。したがって、このクエリを複数回実行する場合は、そのインデックスを 1 回作成してから、必要な回数だけクエリを実行します。

また、合計演算の結果を格納する変数を作成して、可能な限り実行しないようにします。

DECLARE @sumVal AS INT

SET @sumVal = SELECT SUM(Importe) 
        FROM #POS CTACTE2
       WHERE CTACTE2.CodComitente = #POS.CodComitente  
         AND CTACTE2.CodMoneda = #POS.CodMoneda
         AND CTACTE2.EstaAnulado = 0 
         AND (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) > 0 
              OR
             (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) = 0 
              AND (#POS.CodCtaCorrienteMon >= CTACTE2.CodCtaCorrienteMon)))

UPDATE #POS SET SaldoDespuesEvento = @sumVal
WHERE #POS.EstaAnulado = 0 AND #POS.EsSaldoAnterior = 0
于 2013-11-08T20:18:45.437 に答える
0

クエリ プランなしでは多くのことを助けることは困難ですが、FechaLiquidacion 列と CodCtaCorrienteMon 列にまだインデックスがない場合は、データベースのストレージ スペースが問題にならない限り、それらを作成することでパフォーマンスが向上すると仮定します。

于 2013-11-08T18:15:03.290 に答える