Dans les requêtes ci-dessous, les deux plans d'exécution devraient effectuer 1 000 recherches sur un index unique.
Les recherches sont motivées par un balayage ordonné sur la même table source, donc devraient apparemment finir par rechercher les mêmes valeurs dans le même ordre.
Les deux boucles imbriquées ont <NestedLoops Optimized="false" WithOrderedPrefetch="true">
Quelqu'un sait pourquoi cette tâche coûte 0,172434 dans le premier plan mais 3,01702 dans le second?
(La raison de la question est que la première requête m'a été suggérée comme une optimisation en raison du coût apparemment beaucoup plus bas du plan. Il me semble en fait que cela fait plus de travail, mais j'essaie simplement d'expliquer l'écart. .)
Installer
CREATE TABLE dbo.Target(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);
CREATE TABLE dbo.Staging(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);
INSERT INTO dbo.Target
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1,
master..spt_values v2;
INSERT INTO dbo.Staging
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1;
Lien Requête 1 «Coller le plan»
WITH T
AS (SELECT *
FROM Target AS T
WHERE T.KeyCol IN (SELECT S.KeyCol
FROM Staging AS S))
MERGE T
USING Staging S
ON ( T.KeyCol = S.KeyCol )
WHEN NOT MATCHED THEN
INSERT ( KeyCol, OtherCol )
VALUES(S.KeyCol, S.OtherCol )
WHEN MATCHED AND T.OtherCol > S.OtherCol THEN
UPDATE SET T.OtherCol = S.OtherCol;
Lien Requête 2 «Coller le plan»
MERGE Target T
USING Staging S
ON ( T.KeyCol = S.KeyCol )
WHEN NOT MATCHED THEN
INSERT ( KeyCol, OtherCol )
VALUES( S.KeyCol, S.OtherCol )
WHEN MATCHED AND T.OtherCol > S.OtherCol THEN
UPDATE SET T.OtherCol = S.OtherCol;
Requête 1
Requête 2
Ce qui précède a été testé sur SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64)
@Joe Obbish souligne dans les commentaires qu'une repro plus simple serait
SELECT *
FROM staging AS S
LEFT OUTER JOIN Target AS T
ON T.KeyCol = S.KeyCol;
contre
SELECT *
FROM staging AS S
LEFT OUTER JOIN (SELECT * FROM Target) AS T
ON T.KeyCol = S.KeyCol;
Pour la table intermédiaire de 1 000 lignes, les deux ci-dessus ont toujours la même forme de plan avec des boucles imbriquées et le plan sans que la table dérivée n'apparaisse moins cher, mais pour une table intermédiaire de 10 000 lignes et la même table cible que ci-dessus, la différence de coûts change le plan forme (avec une analyse complète et une fusion fusionnée semblant relativement plus attrayante que les recherches coûteuses) montrant que cet écart de coût peut avoir des implications autres que simplement rendre la comparaison des plans plus difficile.