Imaginez que vous ayez la structure de table suivante:
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
et ToPositionId
sont des positions de stock. Certains ID de poste ont une signification particulière, par exemple 0
. Un événement de ou vers 0
signifie que le stock a été créé ou supprimé. De 0
pourrait être stocké à partir d'une livraison et 0
pourrait être une commande expédiée.
Ce tableau contient actuellement environ 5,5 millions de lignes. Nous calculons la valeur des stocks pour chaque produit et nous positionnons dans une table de cache selon un calendrier à l'aide d'une requête qui ressemble à ceci:
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
Même si cela se termine dans un délai raisonnable (environ 20 secondes), j'ai l'impression que c'est une façon assez inefficace de calculer les valeurs des actions. Nous faisons rarement autre chose que INSERT
: s dans ce tableau, mais parfois nous entrons et ajustons la quantité ou supprimons une ligne manuellement en raison d'erreurs des personnes générant ces lignes.
J'ai eu l'idée de créer des «points de contrôle» dans une table séparée, de calculer la valeur jusqu'à un moment précis et de l'utiliser comme valeur de départ lors de la création de notre table de cache de quantité de stock:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
Le fait que nous changions parfois des lignes pose un problème, dans ce cas, nous devons également nous rappeler de supprimer tout point de contrôle créé après la ligne de journal que nous avons modifiée. Cela pourrait être résolu en ne calculant pas les points de contrôle jusqu'à présent, mais en laissant un mois entre maintenant et le dernier point de contrôle (nous apportons très très rarement des modifications aussi lointaines).
Le fait que nous ayons parfois besoin de modifier des lignes est difficile à éviter et j'aimerais pouvoir continuer à le faire, ce n'est pas affiché dans cette structure mais les événements de journal sont parfois liés à d'autres enregistrements dans d'autres tables, et en ajoutant une autre ligne de journal obtenir la bonne quantité n'est parfois pas possible.
Comme vous pouvez l'imaginer, la table des journaux croît assez rapidement et le temps de calcul ne fera qu'augmenter avec le temps.
Donc, à ma question, comment résoudriez-vous cela? Existe-t-il un moyen plus efficace de calculer la valeur actuelle du stock? Mon idée des points de contrôle est-elle bonne?
Nous exécutons SQL Server 2014 Web (12.0.5511)
Plan d'exécution: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
En fait, j'ai donné le mauvais temps d'exécution ci-dessus, 20 secondes était le temps nécessaire à la mise à jour complète du cache. Cette requête prend environ 6 à 10 secondes pour s'exécuter (8 secondes lorsque j'ai créé ce plan de requête). Il y a aussi une jointure dans cette requête qui n'était pas dans la question d'origine.