Sql-Server

MERGE 執行緩慢

  • November 10, 2016

我創建了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 語句不受此問題的影響,因此它們實際上執行得更好。

希望這有助於詹盧卡

引用自:https://dba.stackexchange.com/questions/154828