「 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
にそれがあり、FooPk
が1
のデータベースを1つアップロードした場合、FooPk
と別の@databaseGUID
の2番目のデータベースをアップロードします。NOT MATCHED
は発火するかどうか(テストしただけではありません)。
MERGEを使用する正しい方法はどちらですか?
あなたの最善のアプローチは、潜在的なアクションごとに別々のステートメントを使用し、それらを直列化可能なトランザクションに入れることです。面白いセマンティクスや「ベストプラクティス」違反のない、試行された真のステートメントを使用でき、間違った結果のバグや潜在的なインデックスの破損など、この投稿で概説しているすべての問題を回避できます。