Immagina di avere la seguente struttura di tabella:
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
e ToPositionId
sono posizioni azionarie. Alcuni ID posizione: ad esempio hanno un significato speciale 0
. Un evento da o verso 0
indica che lo stock è stato creato o rimosso. Da 0
potrebbe essere stock da una consegna e 0
potrebbe essere un ordine spedito.
Questa tabella contiene attualmente circa 5,5 milioni di righe. Calcoliamo il valore delle scorte per ciascun prodotto e la posizione in una tabella di cache in una pianificazione utilizzando una query simile a questa:
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
Anche se questo si completa in un ragionevole lasso di tempo (circa 20 secondi), ritengo che questo sia un modo abbastanza inefficiente per calcolare i valori delle azioni. Raramente facciamo altro che INSERT
: s in questa tabella, ma a volte entriamo e regoliamo la quantità o rimuoviamo una riga manualmente a causa di errori da parte delle persone che generano queste righe.
Ho avuto l'idea di creare "checkpoint" in una tabella separata, di calcolare il valore fino a un determinato momento e di usarlo come valore iniziale durante la creazione della nostra tabella cache quantità stock:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
Il fatto che a volte cambiamo le righe pone un problema a questo, in quel caso dobbiamo anche ricordare di rimuovere qualsiasi checkpoint creato dopo la riga di registro che abbiamo modificato. Ciò potrebbe essere risolto non calcolando i punti di controllo fino ad ora, ma lasciando un mese tra ora e l'ultimo punto di controllo (molto raramente apportiamo modifiche molto indietro).
Il fatto che a volte abbiamo bisogno di cambiare le righe è difficile da evitare e vorrei poterlo fare ancora, non è mostrato in questa struttura ma gli eventi di registro sono talvolta legati ad altri record in altre tabelle e aggiungendo un'altra riga di registro per ottenere la giusta quantità a volte non è possibile.
La tabella dei registri sta crescendo piuttosto velocemente e il tempo di calcolo aumenterà solo con il tempo.
Quindi alla mia domanda, come lo risolveresti? Esiste un modo più efficiente per calcolare il valore attuale dello stock? La mia idea di checkpoint è buona?
Stiamo eseguendo SQL Server 2014 Web (12.0.5511)
Piano di esecuzione: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
In realtà ho dato il tempo di esecuzione sbagliato sopra, 20s è stato il tempo impiegato dall'aggiornamento completo della cache. L'esecuzione di questa query richiede circa 6-10 secondi (8 secondi quando ho creato questo piano di query). C'è anche un join in questa query che non era nella domanda originale.