2016-01-19 35 views
2

如何加快这个相当简单的UPDATE查询?它已经运行了5个多小时!如何加速具有数百万行的简单UPDATE查询?

我基本上通过加入一个新的表来替换表中的SourceID,该表包含旧ID和新ID。所有这些字段都是VARCHAR(72),并且必须保持这种状态。

Pub_ArticleFaculty表有8354474行(830万)。 ArticleAuthorOldNew有99326472行(9930万),只有你看到下面的2个字段。

所有这些字段都有单独的非聚集索引。有没有更好的方式来编写这个查询,使其运行速度更快?

UPDATE PF 
     SET PF.SourceId = AAON.NewSourceId 
    FROM AA..Pub_ArticleFaculty PF WITH (NOLOCK) 
     INNER JOIN AA2..ArticleAuthorOldNew AAON WITH (NOLOCK) 
        ON AAON.OldFullSourceId = PF.SourceId 
+0

一旦它完成,你永远需要再次做到这一点? –

+0

您的数据库处于什么恢复模式(完整,简单,批量检测)?您的交易日志是否足够大? –

+0

该数据库现在处于FULL恢复模式。也许因为它处于测试环境中,可以起飞一个小时左右。我不会再运行这个,我不知道如何判断日志是否大小合适。我甚至不关心日志记录,因为如果需要我们有数据库备份。 – Andy

回答

1

根据我的经验,循环更新以使其在每次迭代中行数很少时是一个好方法。更新每次迭代的理想行数很大程度上取决于您的环境和您正在使用的表。我通常每次迭代约有1,000 - 10,000行。

SET ROWCOUNT 1000 -- Set the batch size (number of rows to affect each time through the loop). 
WHILE (1=1) BEGIN 

    UPDATE PF 
    SET NewSourceId = 1 
    FROM AA..Pub_ArticleFaculty PF WITH (NOLOCK) 
      INNER JOIN AA2..ArticleAuthorOldNew AAON WITH (NOLOCK) 
         ON AAON.OldFullSourceId = PF.SourceId 
    WHERE NewSourceId IS NULL -- Only update rows that haven't yet been updated. 

    -- When no rows are affected, we're done! 
    IF @@ROWCOUNT = 0 
     BREAK 
END 
SET ROWCOUNT 0 -- Reset the batch size to the default (i.e. all rows). 
GO 
2

如果要重设全部或几乎全部的值,那么将update是相当昂贵的。这是由于日志记录和更新的开销。你可以采取替代

一种方法是insert到一个临时表,然后再截断,然后重新插入:

select pf.col1, pf.col2, . . . , 
     coalesce(aaon.NewSourceId, pf.sourceid) as SourceId 
into temp_pf 
from AA..Pub_ArticleFaculty PF LEFT JOIN 
    AA2..ArticleAuthorOldNew AAON 
    on AAON.OldFullSourceId = PF.SourceId; 

truncate table AA..Pub_ArticleFaculty; 

insert into AA..Pub_ArticleFaculty 
    select * from temp_pf; 

注意:您应该可以肯定的是,在原表中的列匹配的临时表或者更好的是,在insert中明确列出列。

我也应该注意到,主要的好处是当你的恢复模式很简单或者是批量记录。原因是截断日志记录select intoinsert . . . select是最小的(请参阅here)。这种记录的节省可能非常显着。

+1

将使用大容量恢复模式来减少记录以及我可以尝试你提到的这种方法,但不知道我对截断表的感觉很好,因为它有超过30个字段(不是我的设计,对我可怜......哈哈!)。太多的错误空间,我认为 – Andy

+0

@AndyDesRosiers ......你可以把数据放到一个临时表中,然后重新命名表格,而不是重新插入值。这一步是为了保留约束,触发器等等。 –

0

我没有足够的观点来评论这个问题。所以我将其添加为答案。你可以检查基本的

  1. 在表上的任何触发器?如果是这样的话,那么你的更新行数就会达到那么多倍。如果存在这样的链,这将是性能下降的原因。

  2. 在连接列上有索引吗?

  3. 在其他情况下,系统表现良好吗?验证系统是否有足够的电量

但是如果处理正确,800万条记录运行时间不会超过1分钟。 5个小时意味着一些别的地方出了问题

1

我会

  • 上禁用PF.SourceId
  • 运行更新索引
  • 然后重建索引

我不t在你正在更新的桌子上得到NOLOCK

UPDATE PF 
SET PF.SourceId = AAON.NewSourceId 
FROM AA..Pub_ArticleFaculty PF 
INNER JOIN AA2..ArticleAuthorOldNew AAON WITH (NOLOCK) 
     ON AAON.OldFullSourceId = PF.SourceId 
     AND PF.SourceId <> AAON.NewSourceId 
+0

我已经采取了关闭NOLOCK现在和cha使数据库暂时以SIMPLE完全恢复模式运行,并添加WHERE LIKE子句以在单独的查询中以块运行数据。这似乎加快了很多。虽然我很好奇禁用索引,但我认为它的全部目的是使搜索和加入更快?但是,是因为我们正在更新该字段,它使索引运行速度变慢? – Andy

+0

索引维护需要时间。尝试伤害什么? – Paparazzi

相关问题