SQL Server-需要在包含10亿条记录的表中回填列

SQL Server-需要在包含10亿条记录的表中回填列,sql,sql-server-2008,bulkinsert,Sql,Sql Server 2008,Bulkinsert,我需要在现有的sql server表(a)中用十亿条记录将datetime列回填到中。 Im将目标表(A)与主键(ID)上的父表(B)进行内部连接,然后检索日期。 不幸的是,我在date列上没有索引,这导致更新非常缓慢。 我无法在日期列(ID为include)上创建索引,因为在线索引创建正在消耗整个tlog(最大150gb),并且offine索引构建超出范围 UPDATE A SET A.DATE = ZZ.DATE FROM A INNER JOIN

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

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;
任何专家建议以更快或更有效的方式进行回填


谢谢

听起来像是分块更新的例子。顺便提一下,最近有人就这个话题写了一篇非常详尽的文章()。它处理日志管理问题

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


您可以使用
选择一系列行,其中ID介于@a和@b之间。如果
ID
被索引,则可以避免表扫描,并可以进行增量数据提取。

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

另一件事是,你提到你不能做在线索引创建,你可以做在线索引更新/重建,你可以在ID上向你的集群索引添加日期列,在集群索引中包括你的[date]。因为在我的查询中,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

声明@ID BIGINT
从列表中选择@ID=MIN(ID)
而@ID

如果您处于物理上无法进行批量数据更改的情况下,您将面临很大的风险。如果有人意外删除了索引,您将无法恢复该索引……您为什么要访问表a两次?这似乎是不必要的性能问题。我插入100K或有时1mil循环以避免锁定/性能问题,无法直接与父表联接感谢Ljh,但我无法使用此查询,因为它将直接更新生产系统(隔离模式:读取已提交),这将导致锁定,因为这两个表都是由应用层高度更新的。这就是我使用额外的内部联接并选择具有nolock的行的原因,以便至少行查找(在我的查询中)不会导致任何锁定稍微延迟代码,添加(nolock)对于表B。关于表A,无论您使用哪种查询来更新表A,行或页,或键范围,都取决于您实际更新的程度,它们将被设置更新锁,这就是为什么我在每个表中添加提交传输,在每个批处理完成后,锁将被释放。当然,在更新锁期间,您的应用层不能更新相同的内容行或相同的范围,但查询将是可以的,因为共享锁与更新锁兼容。如果你说你的查询没有锁或更少锁,我认为这是不对的。我可能错了…谢谢ljh和usr..你们给了我正确的方向,下面是我的更新查询。这个查询每分钟更新200万次,就像我原来的查询一样ry一天做了15 mil太棒了!!说到你的问题,你知道的最多。你可以一般性地编写循环,传入一次要更新的记录数、日志备份位置,并添加一个检查以查看外部进程是否想要优雅地终止循环。例如:
(如果存在)(从dbo.RecordControls中选择1,其中ProcedureName=N'up\U UpdateProductDates'和[State]=“INTENT\U STOP”)开始-中断;结束
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