我有一个包含持久数据的表格。现在,当我查询它时,我还有一个非常复杂的公用表达式(CTE),用于计算结果所需的值,并且我需要将缺失的行插入到持久表中。最终,我希望选择由 CTE 确认的所有行组成的结果,但如果它们已经在表格中,则使用来自表格的数据,并且我需要知道一行是否刚刚被插入。
简化后,此操作如下(如果您想尝试运行以下代码,请将其作为正常查询运行):
-- Set-up of test data, this would be the persisted table
DECLARE @target TABLE (id int NOT NULL PRIMARY KEY) ;
INSERT INTO @target (id) SELECT v.id FROM (VALUES (1), (2)) v(id);
-- START OF THE CODE IN QUESTION
-- The result table variable (will be several columns in the end)
DECLARE @result TABLE (id int NOT NULL, new bit NOT NULL) ;
WITH Source AS (
-- Imagine a fairly expensive, recursive CTE here
SELECT * FROM (VALUES (1), (3)) AS Source (id)
)
MERGE INTO @target AS Target
USING Source
ON Target.id = Source.id
-- Perform a no-op on the match to get the output record
WHEN MATCHED THEN
UPDATE SET Target.id=Target.id
WHEN NOT MATCHED BY TARGET THEN
INSERT (id) VALUES (SOURCE.id)
-- select the data to be returned - will be more columns
OUTPUT source.id, CASE WHEN $action='INSERT' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END
INTO @result ;
-- Select the result
SELECT * FROM @result;
我不喜欢WHEN MATCHED THEN UPDATE
这部分,我宁愿去掉冗余的更新,但这样就无法在OUTPUT
子句中获取结果行了。
这是完成和返回数据最有效的方式吗?
还是说有更有效的解决方案,例如通过使用SELECT
预先计算结果,然后执行将new=0
的行插入的操作,而不使用MERGE
?由于查询计划基本上归结为"Clustered Index Merge",与单独的SELECT
后跟INSERT
变体相比,在性能上对我来说不太清楚。并且我想知道SQL Server(2008 R2 with CU1)是否真的足够聪明,能够看出UPDATE
是一个无操作(例如,并不需要写入)。