Pregunta

Tengo una tabla con algunos datos persistentes. Ahora, cuando lo considero, también tengo un CTE bastante complejo que calcula los valores requeridos para el resultado y necesito insertar filas faltantes en la tabla persistente. Al final, quiero seleccionar el resultado que consta de todas las filas identificadas por el CTE pero con los datos de la tabla si ya estaban en la tabla, y necesito la información si una fila se ha insertado o no.

Simplified esto funciona como este (el siguiente código se ejecuta como una consulta normal si desea probarlo):

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

No me gusta el WHEN MATCHED THEN UPDATE Parte, prefiero dejar la actualización redundante lejos, pero luego no obtengo el resultado de la fila en el OUTPUT cláusula.

¿Es esta la forma más eficiente de hacer este tipo de datos de completar y devolver?

O habría una solución más eficiente sin MERGE, por ejemplo, previamente computando el resultado con un SELECT y luego realizar un INSERT de las filas que son new=0? Tengo dificultades para interpretar el plan de consulta, ya que básicamente se reduce a una "fusión del índice agrupado" que es bastante vago para mí en cuanto al rendimiento en comparación con el separado SELECT seguido por INSERT variante. Y me pregunto si SQL Server (2008 R2 con CU1) es realmente lo suficientemente inteligente como para ver que el UPDATE es un no-op (por ejemplo, no se requiere escritura).

¿Fue útil?

Solución

Puede declarar una variable ficticia y establecer su valor en la cláusula coincidente.

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

Creo que debería ser menos costoso que la actualización real de la tabla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top