我只是想从“优化 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 上传一个数据库FooPk
,1
那么我用 aFooPk
和另一个不同的数据库上传第二个数据库,@databaseGUID
我不确定是否NOT MATCHED
会触发(刚刚测试过,它不会)。
哪种方式是使用 MERGE 的正确方式?
我敢说,您最好的方法是对每个潜在操作使用单独的语句,并将它们放入可序列化的事务中。你可以使用经过验证的真实陈述,没有有趣的语义或“最佳实践”违规,你可以避免我在这篇文章中概述的所有问题,包括错误的结果错误和潜在的索引损坏: