MERGE 執行緩慢
我創建了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 和另一個站點:
http://www.sqlservercentral.com/Forums/Topic1465931-391-1.aspx
好的,看看你的程式碼,看起來你正試圖一次完成所有事情(這通常是一個好主意)。在這種情況下,您使用的是 WHEN NOT MATCHED 謂詞,它需要完全外連接才能在一次傳遞中包含匹配的行和不匹配的行。單獨的 DELETE 和 UPDATE 語句不受此問題的影響,因此它們實際上執行得更好。
希望這有助於詹盧卡