2

我需要将 datetime 列回填到现有的具有十亿条记录的 sql server 表 (A) 中。我在主键(ID)上将目标表(A)与父表(B)内部连接,然后检索日期。不幸的是,我在日期列上没有索引,这导致更新非常慢。我无法在 Date 列(包含 ID)上创建索引,因为在线索引创建占用了整个 tlog(最大 150gb)并且离线索引构建超出了范围。

UPDATE  A
    SET A.DATE = ZZ.DATE
FROM    A
        INNER JOIN
        (SELECT TOP 100000 A.ID,
                           B.DATE
         FROM   A WITH (NOLOCK)
                INNER JOIN
                B WITH (NOLOCK)
                -- parent table
                ON A.ID = B.ID
         WHERE  A.DATE IS NULL) AS ZZ
        ON ZZ.ID = A.ID;

任何专家建议以更快或更有效的方式执行回填。

谢谢

4

3 回答 3

1

听起来像是分块更新的案例。顺便说一句,最近有一篇关于这个主题的非常详尽的文章(http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes)。它处理日志管理问题。

基本上,您应该将所做的更新分成尽可能大的批次,同时不会导致过多的日志使用。您可以在 A 上拆分(更新 A.ID 的范围)或在 b 上拆分(根据 B 上索引的某些数据范围(例如聚集索引或任何其他索引)从 B 中提取数据。

使用 选择一系列行WHERE ID BETWEEN @a AND @b。如果ID被索引,您可以避免表扫描并且可以进行增量数据拉取。

于 2013-03-15T22:32:39.930 回答
0

请尝试以下代码,它删除了一次性内部连接,并按批次提交。删除一次性哈希连接可能对您没有太大帮助,但也许值得一试。

另一件事是,您提到您不能进行在线索引创建,您可以进行在线索引更新/重新构建,您可以将日期列添加到 ID 上的集群索引中,将您的 [日期] 包含在集群索引中. 由于在我的查询中,where 子句有 ID 作为条件,还有 [date],所以,如果你可以将 [date] 添加到你的 ID 索引中,它将对性能有很大帮助,它不会有表扫描,只有簇索引搜索。


DECLARE @ID BIGINT
SELECT @ID = MIN(ID) FROM A
WHILE @ID < IDENT_CURRENT('DBO.A')
BEGIN
    BEGIN TRAN
        UPDATE A
        SET A.DATE = B.DATE
        FROM A
        INNER JOIN B (nolock)
        ON A.ID = B.ID
        WHERE A.ID BETWEEN @ID AND @ID + 100000
        AND A.DATE IS NULL
    COMMIT TRAN
    SET @ID = @ID + 100000
END 

于 2013-03-16T08:47:27.563 回答
0
UPDATE  A
    SET A.DATE = ZZ.DATE
FROM    A
        INNER JOIN
        (SELECT  A.ID, B.DATE
         FROM   A WITH (NOLOCK)
                INNER JOIN
                B WITH (NOLOCK)
                ON A.ID = B.ID

         WHERE  A.DATE IS NULL AND A.ID BETWEEN @a and @a + 100000
) AS ZZ
ON ( ZZ.ID = A.ID )
SET @X = @X + 100000
WAITFOR DELAY '00:00:05'
END
于 2013-03-17T03:16:15.060 回答