使用last_value + over的大型sql表

时间:2017-04-25 13:02:39

标签: sql sql-server database

首先,我不是DBA,这篇文章包含了一些丑陋的 sql代码。 :)

上下文

我有一个表格,代表我所有的产品库存活动(在SQL" TP_MOVI"中),从流程开始到结束。在这一行之后,一个产品(在SQL" CODIGO"中)可能在多个位置具有平衡(在SQL" ARMAZEM"中)。

在表格中,我有各种类型的活动,我的工作是总结它,例如,所有产品的余额,直到当前日期或参数化日期。我的逻辑是通过使用LAST_VALUE() OVER()条款来获得所有产品+地点的最后记录,从而产生所有地方的平衡。

我的表目前有超过1 000 000条记录,而且现在,当我尝试从此表中检索数据时,它会导致一些中断,当然,还会延迟检索数据。 我非常确定我的SQL代码不正确并且导致了这个问题,你能帮我解决这个问题吗?

我一直在阅读有关陈述WITH NO LOCK的内容,是否有帮助?

内容 - SQL代码

CREATE TABLE [MOVIMENTACOES](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [DATA] [datetime] NULL,
    [CODIGO] [varchar](20) NULL,
    [ARMAZEM] [int] NULL,
    [TP_MOVI] [varchar](10),
    [QUANTIDADE] [float] NULL,
    [SALDO] [float] NULL,
    [ATV] [bit] NULL)

INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',18,'PROD',0,10,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',18,'PROD',10,15,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','456789',19,'PROD',0,20,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','456789',19,'PROD',20,15,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',28,'PROD',0,6,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',28,'SALE',6,-6,1)

SELECT 
    MOV.ID,
    MOV.DATA, MOV.CODIGO, MOV.ARMAZEM, MOV.TP_MOVI,
    MOV.SALDO,
    MOV.QUANTIDADE,
    MOV.SALDO + LAST_VALUE(MOV.QUANTIDADE) OVER(ORDER BY MOV.DATA ROWS UNBOUNDED PRECEDING) AS SALDO_ACUMULADO
FROM MOVIMENTACOES MOV

    LEFT OUTER JOIN MOVIMENTACOES MOV2 ON
        MOV2.CODIGO = MOV.CODIGO AND        
        MOV2.ARMAZEM = MOV.ARMAZEM AND
        MOV2.ID > MOV.ID
        AND MOV2.DATA <= '2017-04-25 07:00:00'
WHERE
    MOV2.ID IS NULL
    AND MOV.DATA <= '2017-04-25 07:00:00'

以下是架构和数据的一些示例:http://rextester.com/XIXCB97220

2 个答案:

答案 0 :(得分:3)

包含计算结果的计算列可能会提高SELECT次。{
您可能还必须检查索引和键
我没有看到任何主键,例如,将列[ID]设置为主键将有助于使用 它会在其上创建一个CLUSTERED INDEX (这将用于减少SELECT)的性能问题。

答案 1 :(得分:3)

根据您的评论&amp;预期的结果似乎只是想要每个(CODIGO,ARMAZEM)组合的最新行(=具有最高ID的行)。您的SALDO_ACUMULADO计算与SALDO + QUANTIDADE完全相同。这转换为简单的ROW_NUMBER:

WITH cte AS
 (
   SELECT 
      MOV.ID,
      MOV.DATA, MOV.CODIGO, MOV.ARMAZEM, MOV.TP_MOVI,
      MOV.SALDO,
      MOV.QUANTIDADE,
      MOV.SALDO + MOV.QUANTIDADE AS SALDO_ACUMULADO,
      ROW_NUMBER() OVER(PARTITION BY CODIGO, ARMAZEM ORDER BY MOV.ID DESC) AS rn
    FROM MOVIMENTACOES MOV
    WHERE DATA <= '2017-04-25 07:00:00'
 )
SELECT *
FROM cte
WHERE rn = 1
相关问题