Stellen Sie sich vor, Sie haben die folgende Tabellenstruktur:
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
und ToPositionId
sind Aktienpositionen. Einige Positions-IDs haben beispielsweise eine besondere Bedeutung 0
. Ein Ereignis von oder bis 0
bedeutet, dass ein Bestand erstellt oder entfernt wurde. Von 0
könnte Lager von einer Lieferung sein und 0
könnte eine versendete Bestellung sein.
Diese Tabelle enthält derzeit rund 5,5 Millionen Zeilen. Wir berechnen den Bestandswert für jedes Produkt und die Position in einer Cache-Tabelle nach einem Zeitplan mithilfe einer Abfrage, die ungefähr so aussieht:
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
Obwohl dies in angemessener Zeit (ca. 20 Sekunden) abgeschlossen ist, halte ich dies für eine ziemlich ineffiziente Methode zur Berechnung der Aktienwerte. Wir machen selten etwas anderes als INSERT
: s in dieser Tabelle, aber manchmal gehen wir hinein und passen die Menge an oder entfernen eine Zeile manuell aufgrund von Fehlern der Personen, die diese Zeilen generieren.
Ich hatte die Idee, "Prüfpunkte" in einer separaten Tabelle zu erstellen, den Wert bis zu einem bestimmten Zeitpunkt zu berechnen und diesen als Startwert beim Erstellen unserer Bestandsmengen-Cache-Tabelle zu verwenden:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
Die Tatsache, dass wir manchmal Zeilen ändern, stellt ein Problem dar. In diesem Fall müssen wir auch daran denken, alle Prüfpunkte zu entfernen, die nach der von uns geänderten Protokollzeile erstellt wurden. Dies könnte gelöst werden, indem die Kontrollpunkte bis jetzt nicht berechnet werden, sondern ein Monat zwischen jetzt und dem letzten Kontrollpunkt verbleibt (wir nehmen sehr, sehr selten Änderungen so weit zurück).
Die Tatsache, dass wir manchmal Zeilen ändern müssen, ist schwer zu vermeiden, und ich möchte dies weiterhin tun können. Dies wird in dieser Struktur nicht angezeigt, aber die Protokollereignisse sind manchmal mit anderen Datensätzen in anderen Tabellen verknüpft und fügen eine weitere Protokollzeile hinzu Die richtige Menge zu bekommen ist manchmal nicht möglich.
Die Protokolltabelle wächst, wie Sie sich vorstellen können, ziemlich schnell und die Zeit zum Berechnen wird nur mit der Zeit zunehmen.
Also auf meine Frage, wie würden Sie das lösen? Gibt es eine effizientere Methode zur Berechnung des aktuellen Aktienwerts? Ist meine Vorstellung von Checkpoints gut?
Wir führen SQL Server 2014 Web (12.0.5511) aus.
Ausführungsplan: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
Ich habe oben tatsächlich die falsche Ausführungszeit angegeben. 20s war die Zeit, die die vollständige Aktualisierung des Caches in Anspruch nahm. Die Ausführung dieser Abfrage dauert ungefähr 6-10 Sekunden (8 Sekunden, als ich diesen Abfrageplan erstellt habe). Es gibt auch einen Join in dieser Abfrage, der nicht in der ursprünglichen Frage enthalten war.