3

重要: これを SQL Server 2000 互換にする必要があります。

累積合計が必要ですが、現在の日付フィールドに基づいて、現在使用しているような更新クエリは機能しますが、非常に遅いです (醜い暗黙の RBAR 三角結合):

UPDATE #RPT 
SET DailySumAccum = 
      (SELECT SUM(COALESCE(CTACTE2.Amount,0))
       FROM #RPT_CTACTE CTACTE2
       WHERE CTACTE2.IsAvailable = #RPT_CTACTE.IsAvailable 
         AND CTACTE2.CodCustomer = #RPT_CTACTE.CodCustomer  
         AND CTACTE2.ItemType = #RPT_CTACTE.ItemType  
         AND CTACTE2.CodItem = #RPT_CTACTE.CodItem 
         AND EsCtaCorrienteMon = -1 
         AND DATEDIFF(day, CTACTE2.OrderDate, #RPT_CTACTE.OrderDate) >= 0) 
WHERE #RPT_CTACTE.EsSaldoAnterior = 0
  AND EsCtaCorrienteMon = -1

合計を実行するためにカーソル メソッドを使用してみましたが、RBAR の問題を修正できません。日付の比較がまだ存在し、それでも非常に遅いことがわかります。

-- this is inside the cursor

IF (@EsCtaCorrienteMon = -1)
BEGIN
    SELECT @NetoDiarioAcum = SUM(COALESCE(Amount,0))
    FROM #RPT_CTACTE
    WHERE IsAvailable = @IsAvailable
          AND CodCustomer = @CodCustomer
          AND ItemType = @ItemType
          AND CodItem = @CodItem
          AND EsCtaCorrienteMon = -1
          AND DATEDIFF(day, OrderDate, @OrderDate) >= 0
END IF

したがって、この累積合計の問題は、そこでの日付の比較であり、クエリが非常に遅くなっていることです (10 分間実行した後にコードを停止し、この Update カーソルの実行に 3 秒しかかからないことにコメントしました)、私が持っている行数テストされたのは 28K です。レコード数が増えると、所要時間が指数関数的に増加しているように見えます。そのため、ここで RBAR が実行されていることが問題であると想定しています (「Row-By-Agonizing-Row」を意味します)。

編集:いくつかのテストの後、日付だけが問題ではないように見えます.カーソル内の変数を合計するだけで、この実行中の合計を作成する方法はありますか?

EDIT2:現在、最初の更新(4つのフィールドと日付に基づく1日の合計)を作成する方法を探していますが、より速く、カーソル内にロジックを手動で追加することに近づきましたが、カーソル大きくなりすぎて管理が困難になったので、この場合に最適な (より高速な) ランニング トータル手法はどれでしょうか? そして、ここでそのテクニックをどのように実装しますか? これは単純な現在の合計ではありません。これらのフィールドのいずれかが変更された場合はカットする必要があります。フィールドのEsSaldoAnterior変更は 0 または -1 のみです。このフィールドが 0 の場合、更新は外側のテーブルにのみ影響しますが、このフィールドが -1 の場合でも、内側の現在の合計は合計されます。 EsSaldoAnterior「以前の金額」のようなものを意味し、実行中の合計がゼロから開始されるべきではないことを意味します。最初にこれらの金額の合計を開始する必要があります (存在する場合)。これは、ORDER BY を使用する場合の順序です。

ORDER BY IsAvailable, CodCustomer, ItemType, CodItem, OrderDate, EsSaldoAnterior
4

2 に答える 2

3

変更してみる

AND DATEDIFF(day, CTACTE2.OrderDate, #RPT_CTACTE.OrderDate) >= 0) 

CTACTE2.OrderDate<DATEADD(dd, 0, DATEDIFF(dd, 0, #RPT_CTACTE.OrderDate)+1)

また

CTACTE2.OrderDate<DATEADD(dd, 1, DATEDIFF(dd, 0, #RPT_CTACTE.OrderDate))

この場合、サブクエリはインデックスを使用する必要がありますCTACTE2.OrderDate

于 2013-12-02T15:22:17.230 に答える
1

内部サブセレクトを高速にするには、内部クエリを一時テーブルに関連付けるために使用される列にインデックスを追加する必要があります。

CodCustomer
ItemType
CodItem
EsCtaCorrienteMon
IsAvailable
OrderDate

IsAvailable最も異なる値 (つまり、選択性が高い) を持つ列を最初に追加します。2 つの異なる値しかないため、最初の列はありません。

OrderDate 列をインデックスの最後に保持して、グループ内の高速範囲検索を有効にし、日付比較を効率的にします。グループごとの日付が少ない場合、この比較は問題になりません。

サブセレクトが外側の一時的な行に近い行を見つけるように、このインデックスをクラスター化してみてください。

于 2013-12-12T09:29:12.050 に答える