Sql-Server

MERGE 最佳實踐的說明

  • January 11, 2018

我只是想從“優化 MERGE 語句性能”頁面詢問有關 MSDN 上的某些內容的澄清。

我正在使用一個數據倉庫,它從許多不同的數據庫中獲取記錄並儲存數據。我的倉庫數據庫中的所有表基本上都遵循相同的模式:

CREATE TABLE Foo (
   database_guid UNIQUEIDENTIFIER
   ,FooPk BIGINT
   ,Bar NVARCHAR(20)
   ,Qix NCHAR(10)
   ,CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED (
       database_guid ASC
       ,FooPk ASC
       )
   )
GO

CREATE PROCEDURE [iv].[LoadSomeTable] 
   @databaseGUID UNIQUEIDENTIFIER
AS
BEGIN
   SET NOCOUNT ON

   MERGE Foo
   USING #FooStaging AS Source
   ON Foo.FooPk = Source.FooPk AND Foo.database_guid = @databaseGUID
   WHEN MATCHED THEN
       UPDATE SET Bar = Source.Bar
                 ,Qix = Source.Qix
   WHEN NOT MATCHED THEN
       INSERT (database_guid, FooPk, Bar, Qix)
           VALUES (@databaseGUID, FooPk, Bar, Qix);
END
GO

CREATE TABLE #FooStaging (
   FooPk BIGINT
   ,Bar NVARCHAR(20)
   ,Qix NCHAR(10)
   )

--Data gets loaded in to #FooStaging from a C# call to SqlBulkCopy then calls iv.LoadSomeTable

我現在擔心的是我剛剛從那個 MSDN 頁面上讀到了這個聲明

僅在 ON<merge_search_condition> 子句中指定用於確定源表和目標表中的數據匹配條件的搜尋條件。也就是說,僅指定目標表中與源表的對應列進行比較的列。不要包括與其他值(例如常數)的比較。

讀完之後,我認為我的查詢錯誤,我的合併語句應該是

MERGE Foo
USING #FooStaging AS Source
ON Foo.FooPk = Source.FooPk
WHEN MATCHED AND Foo.database_guid = @databaseGUID THEN
   UPDATE SET Bar = Source.Bar
             ,Qix = Source.Qix
WHEN NOT MATCHED THEN
   INSERT (database_guid, FooPk, Bar, Qix)
       VALUES (@databaseGUID, FooPk, Bar, Qix);

但這對我來說“感覺”不正確,因為該database_guid欄位是主鍵的一部分,所以它不應該包含在on? 如果我有它,然後我WHEN MATCHED用 a 上傳一個數據庫FooPk1然後我用 aFooPk和另一個不同的數據庫上傳第二個數據庫,@databaseGUID我不確定是否NOT MATCHED會觸發(剛剛測試過,它不會)。

哪種方式是使用 MERGE 的正確方式?

我敢說,您最好的方法是對每個潛在操作使用單獨的語句,並將它們放入可序列化的事務中。你可以使用經過驗證的真實陳述,沒有有趣的語義或“最佳實踐”違規,你可以避免我在這篇文章中概述的所有問題,包括錯誤的結果錯誤和潛在的索引損壞:

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