Imagine que você tenha a seguinte estrutura de tabela:
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
são posições de ações. Algumas IDs de posição: s têm um significado especial, por exemplo 0
. Um evento de ou para 0
significa que o estoque foi criado ou removido. De 0
pode haver estoque de uma remessa e de 0
um pedido enviado.
Atualmente, esta tabela possui cerca de 5,5 milhões de linhas. Calculamos o valor do estoque de cada produto e a posição em uma tabela de cache em uma programação usando uma consulta semelhante à seguinte:
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
Embora isso seja concluído em um período de tempo razoável (cerca de 20 segundos), sinto que essa é uma maneira bastante ineficiente de calcular os valores das ações. Raramente fazemos qualquer coisa, exceto INSERT
: s nesta tabela, mas algumas vezes ajustamos a quantidade ou removemos uma linha manualmente devido a erros das pessoas que geram essas linhas.
Tive a ideia de criar "pontos de verificação" em uma tabela separada, calculando o valor até um momento específico e usando-o como valor inicial ao criar nossa tabela de cache de quantidade de estoque:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
O fato de às vezes alterarmos as linhas apresenta um problema, nesse caso, também devemos lembrar de remover qualquer ponto de verificação criado após a linha de log que alteramos. Isso poderia ser resolvido não calculando os pontos de verificação até agora, mas deixe um mês entre agora e o último ponto de verificação (muito raramente fazemos alterações há muito tempo).
É difícil evitar o fato de que às vezes precisamos alterar as linhas e eu gostaria de poder fazer isso ainda, não é mostrado nessa estrutura, mas os eventos de log às vezes são vinculados a outros registros em outras tabelas e adicionando outra linha de log obter a quantidade certa às vezes não é possível.
A tabela de log é, como você pode imaginar, crescendo muito rápido e o tempo para calcular aumentará apenas com o tempo.
Então, para a minha pergunta, como você resolveria isso? Existe uma maneira mais eficiente de calcular o valor atual do estoque? A minha ideia de pontos de verificação é boa?
Estamos executando o SQL Server 2014 Web (12.0.5511)
Plano de execução: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
Na verdade, eu dei o tempo de execução errado acima, 20s foi o tempo que levou a atualização completa do cache. Essa consulta leva cerca de 6 a 10 segundos para ser executada (8 segundos quando eu criei este plano de consulta). Também há uma junção nesta consulta que não estava na pergunta original.