SQL Server中非常大的表的更新或合并

时间:2011-05-14 13:01:38

标签: sql-server-2008 sql-update sql-merge

我需要每天更新一个非常大的(300M记录)和广泛的TABLE1。更新的源数据位于另一个表UTABLE中,该表是TABLE1行的10%-25%但是很窄。两个表都以record_id为主键。

目前,我正在使用以下方法重新创建TABLE1

<!-- language: sql -->
    1) SELECT (required columns) INTO TMP_TABLE1 
    FROM TABLE1 T join UTABLE U on T.record_id=U.record_id  
    2) DROP TABLE TABLE1  
    3) sp_rename 'TMP_TABLE1', 'TABLE1'

然而,我的服务器上需要将近40分钟(SQL Server为60GB的RAM)。我希望获得50%的性能提升 - 我可以尝试其他选项吗?

  1. MERGEUPDATE - 类似下面的代码只适用于非常小的UTABLE表格 - 完整尺寸,所有内容都会挂起:

    <!-- language: SQL -->
    MERGE TABLE1 as target  
    USING UTABLE as source  
    ON target.record_id = source.record_id   
      WHEN MATCHED THEN   
        UPDATE SET Target.columns=source.columns
    
  2. 我听说我可以使用ROWCOUNT执行批量MERGE - 但我不认为它对于300M行表来说足够快。

  3. 任何有用的SQL查询提示?

2 个答案:

答案 0 :(得分:8)

实际上我已经找到了对这些查询的一般建议:使用SQL Merge或Update的想法是非常聪明的,但是当我们需要更新许多记录(即 75M )时,它会失败一张宽大的桌子(即 240M )。

查看下面查询的查询计划,我们可以说TABLE1的TABLE SCAN和最终的MERGE占用了90%的时间。

MERGE TABLE1 as Target  
USING UTABLE as source  
ON Target.record_id = source.record_id   
WHEN MATCHED AND (condition) THEN   
    UPDATE SET Target.columns=source.columns

因此,为了使用MERGE,我们需要:

  1. 减少需要更新的行数,并将此信息正确传递给SQL Server。这可以通过缩小UTABLE或指定缩小待合并部分的其他condition来完成。
  2. 确保要合并的部分适合内存,否则查询运行速度会变慢。减少TABLE1两次会将我的实际查询时间从11小时减少到40分钟。
  3. 正如Mark所说,你可以使用UPDATE语法并使用WHERE子句来缩小要合并的部分 - 这将得到相同的结果。另请避免索引TABLE1,因为这会导致在MERGE期间重建索引的其他工作

答案 1 :(得分:7)

首先,我会发现你的瓶颈在哪里 - 你的CPU是固定的还是空闲的?换句话说 - 您的IO子系统是否能够正确处理负载?

重新创建整个表是很多IO负载,更不用说它会占用大量空间,基本上暂时将表存储两次。

你需要执行一个MERGE - 我可以看到一个简单的更新就足够了。例如:

UPDATE
    TABLE1
SET
    ColumnX = UTABLE.ColumnX
    ...
FROM
    TABLE1
INNER JOIN
    UTABLE ON TABLE1.record_id = UTABLE.record_id

您可以使用ROWCOUNT批量更新,但这不会加快执行速度,只会减少整体锁定。

另外 - 你在桌子上有什么样的索引?在更新之前禁用索引可能会更快,然后从头开始重建它们(仅限非聚簇)。