Question

J'ai une situation où une application "Publisher" maintient essentiellement un modèle de vue à jour en interrogeant une vue très complexe, puis en fusionnant les résultats dans un tableau de modèle de vue dénormalisée, en utilisant des opérations d'insert, de mise à jour et de supprimer séparées.

Maintenant que nous avons mis à niveau vers SQL 2008, j'ai pensé que ce serait le moment idéal pour les mettre à jour avec l'instruction SQL Merge. Cependant, après avoir écrit la requête, le coût du sous-arbre de la déclaration de fusion est de 1214,54! Avec l'ancienne manière, la somme de l'insert / mise à jour / de la suppression n'était que de 0,104 !!

Je ne peux pas comprendre comment une façon plus simple de décrire la même opération exacte pourrait être tellement plus froissée. Vous pouvez peut-être voir l'erreur de mes manières là où je ne peux pas.

Quelques statistiques sur la table: il compte 1,9 million de lignes, et chaque opération de fusion insère, mises à jour ou en suppose plus de 100. Dans mon cas de test, un seul est affecté.

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

Alors, comment cela atteint-il le coût de 1200 sous-arbre? L'accès aux données des tableaux eux-mêmes semble être assez efficace. En fait, 87% du coût de la fusion semble provenir d'une opération de tri vers la fin de la chaîne:

Merge (0%) <- Mise à jour de l'indice (12%) <- Sort (87%) <- (...)

Et ce genre a 0 lignes qui se nourrissent et sortent de lui. Pourquoi faut-il 87% des ressources pour trier 0 lignes?

METTRE À JOUR

J'ai posté le réel (non estimé) Plan d'exécution pour uniquement l'opération de fusion dans un gist.

Pas de solution correcte

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