从timestamp迁移到from-columns的最有效方法

时间:2016-09-01 12:11:41

标签: sql-server sql-server-2012

给定一个包含列的表Orders

id | revision | insertedAt           
1           0   2016-01-01 00:00.000
1           1   2016-01-01 02:00.000
2           0   2016-01-01 02:00.000

id,修订版组合是唯一的。

我如何才能最好地迁移到此:

id | revision | applyFrom           | applyTo
1           0   2016-01-01 00:00.000   2016-01-01 01:99.999
1           1   2016-01-01 02:00.000   9999-31-12 00:00.000
2           0   2016-01-01 02:00.000   9999-31-12 00:00.000

我已经尝试迭代CURSOR并随着时间的推移进行更新。

UPDATE orders SET applyFrom = @newApplyFrom, applyTo = @newApplyTo
WHERE id = @id AND revision = @revision;

但是有2.26亿行,估计运行时间接近60小时,甚至达到指数。

是否有更快的方法来实现相同的结果?我可以根据需要添加索引。目前,(id,revision)上有一个聚簇索引。

2 个答案:

答案 0 :(得分:2)

您可以更新如下:我正在使用潜水并使用选择

显示
;with cte as (
select *, lead(insertedAt,1,'9999-12-31 00:00.000') over(order by id) migdate from Orders
)
select *, case when insertedAt = migdate then '9999-12-31 00:00.000' else DATEADD(S, -1, migdate) end as applyto  from cte

答案 1 :(得分:1)

这是一个包含LEAD和自我加入的版本。不确定大数据集的性能,但我已经包括批处理以防万一。

WITH cte AS (
    SELECT 
        id, 
        revision, 
        insertedAt, 
        applyFrom,
        applyTo,
        LEAD(insertedAt) OVER (PARTITION BY id ORDER BY id, revision) AS newApplyTo
    FROM orders
)
UPDATE TOP (@BatchSize) o SET
     applyFrom = o.insertedAt,
     applyTo = ISNULL(DATEADD(s, -1, o.newApplyTo), '9999-12-31')  
FROM cte o
WHERE 
    o.applyFrom IS NULL AND 
    o.applyTo IS NULL;

我使用的数据集(带结果)是:

Id          revision    insertedAt                  applyFrom                   applyTo
----------- ----------- --------------------------- --------------------------- ---------------------------
1           0           2016-01-01 00:00:00.0000000 2016-01-01 00:00:00.0000000 2016-01-01 01:59:59.0000000
1           1           2016-01-01 02:00:00.0000000 2016-01-01 02:00:00.0000000 9999-12-31 00:00:00.0000000
2           0           2016-01-01 02:00:00.0000000 2016-01-01 02:00:00.0000000 9999-12-31 00:00:00.0000000
3           0           2016-01-01 00:00:00.0000000 2016-01-01 00:00:00.0000000 2016-10-31 23:59:59.0000000
3           1           2016-11-01 00:00:00.0000000 2016-11-01 00:00:00.0000000 2016-11-30 23:59:59.0000000
3           2           2016-12-01 00:00:00.0000000 2016-12-01 00:00:00.0000000 9999-12-31 00:00:00.0000000