使用新序列更新聚合表

时间:2018-05-24 08:06:29

标签: sql-server tsql sql-server-2016

一般情景:

我有一个每个用户的聚合表和有几个度量的日期。 该表每个用户和日期最多可存储10条记录(可能更少,具体取决于用户活动) 有一列是按日期排序的序列。

样品:

CREATE TABLE #Main (UserId int , DateId int , MeasureA numeric(20,2) , MeasureB numeric(20,2), PlayDaySeq int)
INSERT INTO #Main 
    VALUES (188,    20180522    ,75.00,     282287.00,  1),
           (188,    20180518    ,250.00,    1431725.00, 2),
           (188,    20180514    ,25.00,     35500.00,   3),
           (188,    20180513    ,115.00,    67100.00,   4),
           (188,    20180511    ,75.00,     10625.00,   5),
           (188,    20180510    ,40.00,     2500.00,    6),
           (188,    20180509    ,40.00,     750.00,     7),
           (188,    20180508    ,160.00,    16250.00,   8),
           (188,    20180507    ,135.00,    138200.00,  9),
           (188,    20180507    ,150.00,    68875.00,   10)

PlayDaySeq计算为ROW_NUMBER () OVER (PARTITION BY UserID ORDER BY DateId DESC)

以下是用于保存新聚合数据的表:

CREATE TABLE #Inc (UserId int , DateId int , MeasureA numeric(20,2) , MeasureB numeric(20,2), PlayDaySeq int)
INSERT INTO #Inc
    VALUES (188,    20180523    ,225.00,    802921.00,  1)

现在,有一条新记录,所以我使用了以下内容:

INSERT INTO #Main
    SELECT * 
     FROM #Inc I
        WHERE NOT EXISTS 
            (
            SELECT 1 
            FROM #Main M
            WHERE i.UserId = M.UserId
            AND i.DateId = M.DateId
            )

问题

我需要更新PlayDaySeq列,以便新记录为1,其余所有记录将增加1 并删除序列大于10的记录

这样做的最佳方式是什么? 请记住,#main表非常大(250M记录)。

我可以再次运行ROW_NUMBER来更新序列,然后DELETE再次运行大于10的序列, 我正在寻找最有效的方法。

1 个答案:

答案 0 :(得分:1)

更新一行导致每个其他单个记录的更新并不是一个好主意,尽管它不经常发生。就像已经提到的评论一样,我认为不需要这样的专栏。 但是你说你有理由这样我会认为这是真的。

我的建议是在桌面上放下PlayDaySeq并创建一个视图,其中包含以下附加列。

ROW_NUMBER () OVER (PARTITION BY UserID ORDER BY DateId DESC) AS PlayDaySeq

然后,无论您的代码使用该表现在应该使用该视图,都应该保持最小的更改。但你需要测试一下,看看性能如何。此外,如果您将视图更改为索引视图,SQL Server会将值存储为类似于事物的表,当您插入新记录时,它会自动为您更新内容,同样需要测试性能,插入时。

如果我是你,我会更愿意尝试不同的方法,比如将它设为1,2,3我将其设置为100,200,300,因此当插入需求较小时,如每天20条记录,我就不需要了更新休息记录,但只是输入11,12 101,102仍然保持订单正确,并且每晚更新整个表格为100,200,300,以便在第二天重新开始,或者使代码仅在完成时用尽数字,但由于您在使用它时如何陈述其他含义,它可能根本不起作用。