22

いくつかの永続データを含むテーブルがあります。クエリを実行すると、結果に必要な値を計算するかなり複雑な 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

これは、この種のデータを完成させて返す最も効率的な方法ですか?

MERGEまたは、たとえば、 を使用して結果を事前に計算してから、である行の をSELECT実行するなど、 を使用しないより効率的なソリューションはありますか? 基本的に「クラスター化インデックスマージ」に要約されるため、クエリプランを解釈するのが困難です。これは、別のバリアントに続くものと比較して、パフォーマンスに関してかなり曖昧です。また、SQL Server (2008 R2 with CU1) は実際に、何もしない (たとえば、書き込みが不要) ことを確認できるほどスマートなのだろうかと思います。INSERTnew=0SELECTINSERTUPDATE

4

1 に答える 1

35

ダミー変数を宣言し、その値をWHENMATCHED句で設定できます。

 DECLARE @dummy int;
 ...
 MERGE
 ...
 WHEN MATCHED THEN
   UPDATE SET @dummy = 0
 ...

実際のテーブルの更新よりも安価なはずだと思います。

于 2011-05-04T14:10:22.123 に答える