Question

J'ai une table avec des données persistantes en elle. Maintenant, quand je fais une recherche, j'ai aussi un CTE assez complexe qui calcule les valeurs requises pour le résultat et je dois insérer des lignes manquantes dans la table persistante. En fin de compte, je veux choisir le résultat composé de toutes les lignes identifiées par le CTE, mais avec les données de la table si elles étaient déjà dans la table, et je besoin des informations si une ligne a été juste inséré ou non.

simplifié ce fonctionne comme ceci (les pistes de code suivant comme une requête normale si vous voulez l'essayer):

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

Je ne suis pas comme la partie WHEN MATCHED THEN UPDATE, je préfère laisser la mise à jour redondante loin mais je ne suis pas la ligne de résultat dans la clause OUTPUT.

Est-ce la façon la plus efficace de faire ce genre de remplir et de renvoyer des données?

Ou y aurait-il une solution plus efficace sans MERGE, par exemple par pré-calcul du résultat avec un SELECT puis effectuer une INSERT des lignes qui sont new=0? J'ai des difficultés d'interprétation du plan de requête, car il se résume essentiellement à un « index cluster fusion » qui est assez vague pour moi par rapport à la performance sage de la SELECT séparée suivie par la variante de INSERT. Et je me demande si SQL Server (2008 R2 avec CU1) est en fait assez intelligent pour voir que le UPDATE est un no-op (par exemple pas d'écriture nécessaire).

Était-ce utile?

La solution

Vous pouvez déclarer une variable factice et sa valeur dans la clause, égalés.

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

Je crois qu'il devrait être moins cher que la mise à jour de la table réelle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top