In den folgenden Abfragen wird geschätzt, dass beide Ausführungspläne 1.000 Suchvorgänge für einen eindeutigen Index ausführen.
Die Suchvorgänge werden von einem geordneten Scan in derselben Quelltabelle gesteuert, sodass anscheinend dieselben Werte in derselben Reihenfolge gesucht werden sollten.
Beide verschachtelten Schleifen haben <NestedLoops Optimized="false" WithOrderedPrefetch="true">
Weiß jemand, warum diese Aufgabe bei 0.172434 im ersten Plan aber 3.01702 im zweiten kostet?
(Der Grund für die Frage ist, dass mir die erste Abfrage aufgrund der offensichtlich viel geringeren Planungskosten als Optimierung vorgeschlagen wurde. Es sieht für mich tatsächlich so aus, als würde es mehr funktionieren, aber ich versuche nur, die Diskrepanz zu erklären.) .)
Installieren
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;
Abfrage 1 Link "Plan einfügen"
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;
Abfrage 2 Link "Plan einfügen"
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;
Abfrage 1
Abfrage 2
Das Obige wurde unter SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64) getestet.
@ Joe Obbish weist in den Kommentaren darauf hin, dass ein einfacherer Repro wäre
SELECT *
FROM staging AS S
LEFT OUTER JOIN Target AS T
ON T.KeyCol = S.KeyCol;
vs
SELECT *
FROM staging AS S
LEFT OUTER JOIN (SELECT * FROM Target) AS T
ON T.KeyCol = S.KeyCol;
Für die Staging-Tabelle mit 1.000 Zeilen haben beide oben genannten weiterhin dieselbe Planform mit verschachtelten Schleifen und den Plan, ohne dass die abgeleitete Tabelle billiger erscheint. Bei einer Staging-Tabelle mit 10.000 Zeilen und derselben Zieltabelle wie oben ändert sich der Plan jedoch durch die Kostendifferenz Form (mit einem vollständigen Scan- und Merge-Join, der relativ attraktiver zu sein scheint als teure Suchvorgänge), die diese Kostendifferenz aufzeigt, kann andere Auswirkungen haben, als nur den Vergleich von Plänen zu erschweren.