我需要每天更新一个非常大的(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%的性能提升 - 我可以尝试其他选项吗?
MERGE
和UPDATE
- 类似下面的代码只适用于非常小的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
我听说我可以使用ROWCOUNT执行批量MERGE - 但我不认为它对于300M行表来说足够快。
任何有用的SQL查询提示?
答案 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,我们需要:
UTABLE
或指定缩小待合并部分的其他condition
来完成。TABLE1
两次会将我的实际查询时间从11小时减少到40分钟。正如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批量更新,但这不会加快执行速度,只会减少整体锁定。
另外 - 你在桌子上有什么样的索引?在更新之前禁用索引可能会更快,然后从头开始重建它们(仅限非聚簇)。