2017-02-12 51 views
-1

我使用SQL Server 2014并需要在一个表中更新新添加的日期时间类型列。有两个相关的表(均具有> 30个百万条记录):如何优化运行数百万条记录的SQL Server合并语句

表A:

CategoryID, itemID, dataCreated, deleted, some other string properties. 

此表包含不同datecreated每个项目的倍数的记录。

表B:

CategoryID, itemID, LatestUpdatedDate (This is the new added column) 

categoryID两者和itemID是在这个表的索引的一部分。

要更新tableB的的LatestUpdatedDate从表一对匹配CategoryIDItemID,我用下面的合并声明:

merge [dbo].[TableB] with(HOLDLOCK) as t 
using 
(
    select CategoryID,itemID, max(DateCreated) as LatestUpdatedDate 
    from dbo.TableA 
    where TableA.Deleted = 0 
    group by CategoryID,itemID 
) as s on t.CategoryID = s.CategoryID and t.itemID = s.itemID 

when matched then 
    update 
    set t.LatestUpdatedDate = s.LatestUpdatedDate 

when not matched then 
    insert (CategoryID, itemID, LatestUpdatedDate) 
    values (s.CategoryID, s.itemID) 

鉴于数以百万计的在这两个表中的记录,我怎样才能优化这个脚本?还是有其他方式来更好的表现更好吗?

注意:这是一次性脚本并且数据库处于活动状态,将来会有一个触发器添加到tableA中,用于插入以更新tableB中的日期。

+0

关键问题是:做的变化需要原子吗?有没有一段时间你可以独占锁定这个表?如果它不需要是原子的,那么我会把它分成独立的'update'和'insert'语句。那样你就把你的工作打破了一半。我之前被'合并'烧过,表现明智,所以现在我转而离开它。您还可以使用'set rowcount'技巧一次更新较小的批次,而不是一次性锁定整个表格。 –

+0

我应该提到这是一个实时数据库,尽管我可以在晚上/周末期间运行脚本,但流量较少。合并之前你有什么样的性能问题?我不确定在这个关卡表上执行此操作需要多长时间。分钟,小时? – xingkong

+0

合并时,性能与'when not matched'部分一致。你需要弄清楚这些变化是否需要原子化。也就是说:如果表格只是在几个小时内逐渐改变它,或者表格需要一次完全更新(为了一致性),那么可以。如果行y更新但不是行x,您的应用程序是否会中断?请注意,如果您在连接列上没有索引,这将会很慢(无论您以何种方式执行)。添加索引不是会改变应用程序的表格更改,您可以随后删除它们。 –

回答

2

按照Optimizing MERGE Statement Performance,你能做的最好的是:

  • 创建在源表中是独一无二的,覆盖连接列的索引。
  • 在目标表的连接列上创建唯一的聚集索引。

您可以通过在(Deleted, CategoryID, itemID) INCLUDE(DateCreated)创建于TableA索引中MERGE1获得的性能提升。但是,由于这是一次性操作,因此创建此索引所需的资源(时间,CPU,空间)可能不会抵消相对于运行查询而言的性能收益,并依赖于您现有的索引。

+0

是的,因为这是一次性操作,所以我会避免对表本身做任何改变。如果我将它分成多个合并,并且条件如categoryID <500,categoryID> 500 ... – xingkong

+0

,那么它会对我们有帮助。使用具有索引构建的大于50M行的表进行测试,大约需要2分钟才能完成。看起来很好。谢谢。 – xingkong

相关问题