Domanda

Ho una tabella con alcuni dati persistenti in esso. Ora, quando interrogo esso, ho anche un CTE abbastanza complesso che calcola i valori necessari per il risultato e ho bisogno di inserire righe mancanti nella tabella persistente. Alla fine voglio selezionare il risultato che consiste di tutte le righe individuate dalla CTE ma con i dati della tabella se fossero già nella tabella, e ho bisogno le informazioni se una riga è stata appena inserito o meno.

semplificato Questa opere come questa (i seguenti percorsi di codice come una query normale se vi piace di provarlo):

-- 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;

Non mi piace la parte WHEN MATCHED THEN UPDATE, preferirei lasciare l'aggiornamento ridondante via, ma poi non ho ricevuto la riga del risultato nella clausola OUTPUT.

E 'questo il modo più efficace per fare questo tipo di completamento e restituzione di dati?

O ci sarebbe una soluzione più efficiente senza MERGE, ad esempio pre-computing il risultato con un SELECT e quindi eseguire un INSERT delle righe che sono new=0? Ho difficoltà che interpretano il piano di query in quanto si riduce sostanzialmente verso il basso per un "Clustered Index Merge", che è piuttosto vago per me prestazioni-saggio rispetto al SELECT separata seguita da variante INSERT. E mi chiedo se SQL Server (2008 R2 con CU1) è in realtà abbastanza intelligente per capire che la UPDATE è un no-op (richiesto ad esempio senza scrittura).

È stato utile?

Soluzione

Si potrebbe dichiarare una variabile fittizia e impostare il suo valore nella clausola WHEN MATCHED.

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

Credo che dovrebbe essere meno costoso che l'aggiornamento tabella effettiva.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top