次のテーブル構造があるとします。
LogId | ProductId | FromPositionId | ToPositionId | Date | Quantity
-----------------------------------------------------------------------------------
1 | 123 | 0 | 10002 | 2018-01-01 08:10:22 | 5
2 | 123 | 0 | 10003 | 2018-01-03 15:15:10 | 9
3 | 123 | 10002 | 10004 | 2018-01-07 21:08:56 | 3
4 | 123 | 10004 | 0 | 2018-02-09 10:03:23 | 1
FromPositionId
とToPositionId
在庫位置です。一部のポジションID:には特別な意味があります0
。イベントの開始または終了0
は、ストックが作成または削除されたことを意味します。From 0
は配送からの在庫で、to 0
は発送済みの注文です。
このテーブルは現在約550万行を保持しています。次のようなクエリを使用して、各製品の在庫値を計算し、スケジュールに基づいてキャッシュテーブルに配置します。
WITH t AS
(
SELECT ToPositionId AS PositionId, SUM(Quantity) AS Quantity, ProductId
FROM ProductPositionLog
GROUP BY ToPositionId, ProductId
UNION
SELECT FromPositionId AS PositionId, -SUM(Quantity) AS Quantity, ProductId
FROM ProductPositionLog
GROUP BY FromPositionId, ProductId
)
SELECT t.ProductId, t.PositionId, SUM(t.Quantity) AS Quantity
FROM t
WHERE NOT t.PositionId = 0
GROUP BY t.ProductId, t.PositionId
HAVING SUM(t.Quantity) > 0
これは妥当な時間(約20秒)で完了しますが、これは株価の計算方法としてはかなり非効率的だと感じています。INSERT
この表では:s 以外はほとんど行いませんが、これらの行を生成するユーザーのミスにより、手動で数量を調整したり、行を手動で削除したりすることがあります。
別のテーブルに「チェックポイント」を作成し、特定の時点までの値を計算し、在庫数量キャッシュテーブルを作成するときにそれを開始値として使用するというアイデアがありました。
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
行を変更することがあるという事実はこれに問題を引き起こします。その場合、変更したログ行の後に作成されたチェックポイントも削除することを忘れないでください。これは、これまでチェックポイントを計算せずに、現在と最後のチェックポイントの間に1か月を空けることで解決できます(これほど前に変更を加えることはほとんどありません)。
行を変更する必要があるという事実を回避するのは難しいため、これを引き続き実行できるようにしたいのですが、この構造には表示されませんが、ログイベントは他のテーブルの他のレコードに関連付けられ、別のログ行を追加する場合があります適切な量を得ることは時々不可能です。
ログテーブルは、ご想像のとおり、かなり急速に成長しており、計算時間は時間とともに増加します。
だから私の質問に、これをどのように解決しますか?現在の株価を計算するより効率的な方法はありますか?チェックポイントの私の考えは良いものですか?
SQL Server 2014 Web(12.0.5511)を実行しています
実行計画:https : //www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
上記で実際に間違った実行時間を指定しました。キャッシュの完全な更新にかかった時間は20秒でした。このクエリの実行には約6〜10秒かかります(このクエリプランを作成したときは8秒)。このクエリには、元の質問にはなかった結合もあります。