我创建了MERGE语句,以将具有最小所需列集的差异从生产数据库传输到临时数据库。合并后的表格计划用于不同的报告和分析场景(只读)。将差异放入暂存表的整个过程应该很快(至少比当前每天完全获取整个表内容的方法快很多,方法是对所有数据执行 DELETE 然后 INSERT INTO 操作,而不管实际数量多少更改的数据,我估计约为 5%)。
这是一个示例:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET NOCOUNT ON
IF NOT exists(select 1 from StagingDB.sys.tables t join StagingDB.sys.schemas s on t.schema_id = s.schema_id WHERE t.name like 'A' and s.name like 'staging')
BEGIN
SELECT Top 0 [ID],[OID]
INTO [StagingDB].[staging].[A]
From [LiveDB].[dbo].[A];
END;
MERGE INTO [StagingDB].[staging].[A] AS Target
USING (
SELECT [ID], [OID] From [LiveDB].[dbo].[A] where X = 0
) AS Source ([ID],[OID])
ON (Target.[ID] = Source.[ID])
WHEN MATCHED AND (Target.[OID] <> Source.[OID]) THEN
UPDATE SET [OID] = Source.[OID]
WHEN NOT MATCHED BY TARGET THEN
INSERT([ID],[OID]) VALUES(Source.[ID],Source.[OID])
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
IF NOT EXISTS(
SELECT * FROM sys.indexes ix Where ix.name = 'PK_A' AND ix.object_id = OBJECT_ID('[StagingDB].[staging].[A]')
)
BEGIN
ALTER TABLE [StagingDB].[staging].[A] add constraint PK_A primary key CLUSTERED ([ID])
END
这对我的大多数桌子来说运行得非常快。不幸的是,有两个表有更多的行,而且这两个表的更多列在稍后的报告过程中被使用,所以我必须传输更多的数据。
虽然我可以在不到一分钟的时间内为 71 个表运行这种合并命令,但两个有问题的 MERGE 语句每个运行大约 2 小时。我还不知道为什么。
我怀疑日期的数量,还有我比较表格差异的方式。为了确定是否必须运行 UPDATE 语句,我对 Merge 语句中包含的每一列进行比较。因此,如果我有 10 个列,则 MERGE 的更新条件如下所示:
WHEN MATCHED AND (Target.[OID] <> Source.[OID] OR Target.[OID1] <> Source.[OID2] OR Target.[Text1] <> Source.[Text1] OR Target.[varcharlong1] <> Source.[varcharlong1] ) etc...
所以事实证明,这种更新条件检查包括所有列并且不会有索引。暂存表始终在 uniqueidentifier 中有一个聚集的主键,并且(到目前为止)没有额外的索引。
我的问题是:虽然 MERGE 语句对于我们的大多数表都运行得非常快速和高效,但看起来这个过程不适合包含多个列的两个较大的表。在这种情况下,我是否使用 OR 子句正确使用了 MERGE 语句来确保需要更新行,或者有更好的方法吗?有没有更好的方法可以将列子集的增量(更改)快速获取到临时表中?我所有的表都有一个 ROWVERSION,也许这可以用来找出以某种方式更改的行?
不要使用合并,它在大表上总是存在性能问题。自从关键字合并被放入 SQL Server 以来,这一直是一个持续存在的问题。请参阅下面的 Microsoft Connect 和另一个站点:
https://connect.microsoft.com/SQLServer/feedback/details/635778/not-matched-and-matched-parts-of-a-sql-merge-statement-are-not-optimized
http://www.sqlservercentral.com/Forums/Topic1465931-391-1.aspx
好的,看看你的代码,看起来你正试图一次完成所有事情(这通常是一个好主意)。在这种情况下,您使用的是 WHEN NOT MATCHED 谓词,它需要完全外连接才能在一次传递中包含匹配的行和不匹配的行。单独的 DELETE 和 UPDATE 语句不受此问题的影响,因此它们实际上执行得更好。
希望这有助于詹卢卡