Pregunta

Tengo una situación en la que una aplicación de "editor" esencialmente mantiene un modelo de vista actualizado al consultar una vista muy compleja y luego fusionar los resultados en una tabla de modelo de vista desnormalizada, utilizando operaciones de inserción, actualización y actualización separadas.

Ahora que hemos actualizado a SQL 2008, pensé que sería un buen momento para actualizarlos con la declaración SQL Merge. Sin embargo, después de escribir la consulta, ¡el costo subárbol de la declaración de fusión es 1214.54! ¡Con la antigua forma, la suma de la inserción/actualización/eliminación fue solo 0.104!

No puedo entender cómo una forma más directa de describir la misma operación exacta podría ser mucho más horrible. Quizás puedas ver el error de mis caminos donde no puedo.

Algunas estadísticas sobre la tabla: tiene 1.9 millones de filas, y cada operación de fusión inserta, actualiza o elimina más de 100 de ellas. En mi caso de prueba, solo 1 se ve afectado.

-- This table variable has the EXACT same structure as the published table
-- Yes, I've tried a temp table instead of a table variable, and it makes no difference
declare @tSource table
(
    Key1 uniqueidentifier NOT NULL,
    Key2 int NOT NULL,
    Data1 datetime NOT NULL,
    Data2 datetime,
    Data3 varchar(255) NOT NULL, 
    PRIMARY KEY 
    (
        Key1, 
        Key2
    )
)

-- Fill the temp table with the desired current state of the view model, for
-- only those rows affected by @Key1.  I'm not really concerned about the
-- performance of this.  The result of this; it's already good.  This results
-- in very few rows in the table var, in fact, only 1 in my test case
insert into @tSource
select *
from vw_Source_View with (nolock)
where Key1 = @Key1

-- Now it's time to merge @tSource into TargetTable

;MERGE TargetTable as T
USING tSource S
    on S.Key1 = T.Key1 and S.Key2 = T.Key2

-- Only update if the Data columns do not match
WHEN MATCHED AND T.Data1 <> S.Data1 OR T.Data2 <> S.Data2 OR T.Data3 <> S.Data3 THEN
    UPDATE SET
        T.Data1 = S.Data1,
        T.Data2 = S.Data2,
        T.Data3 = S.Data3

-- Insert when missing in the target
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Key1, Key2, Data1, Data2, Data3)
    VALUES (Key1, Key2, Data1, Data2, Data3)

-- Delete when missing in the source, being careful not to delete the REST
-- of the table by applying the T.Key1 = @id condition
WHEN NOT MATCHED BY SOURCE AND T.Key1 = @id THEN
    DELETE
;

Entonces, ¿cómo llega esto al costo de su subárbol 1200? El acceso a los datos desde las tablas en sí parece ser bastante eficiente. De hecho, el 87% del costo de la fusión parece ser de una operación de clasificación cerca del final de la cadena:

Fusionar (0%) <- Actualización del índice (12%) <- sort (87%) <- (...)

Y ese tipo tiene 0 filas que se alimentan dentro y fuera de ella. ¿Por qué se necesita el 87% de los recursos para clasificar las 0 filas?

ACTUALIZAR

Publiqué lo real (no estimado) Plan de ejecución solo para la operación de fusión en una esencia.

No hay solución correcta

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