Nelle query sottostanti si stima che entrambi i piani di esecuzione eseguano 1.000 ricerche su un indice univoco.
Le ricerche sono guidate da una scansione ordinata sulla stessa tabella di origine, quindi apparentemente dovrebbe finire per cercare gli stessi valori nello stesso ordine.
Entrambi i loop nidificati hanno <NestedLoops Optimized="false" WithOrderedPrefetch="true">
Qualcuno sa perché questa attività è costata a 0,172434 nel primo piano ma a 3,01702 nel secondo?
(Il motivo della domanda è che la prima query mi è stata suggerita come un'ottimizzazione a causa del costo del piano apparentemente molto più basso. In realtà mi sembra che faccia più lavoro ma sto solo cercando di spiegare la discrepanza .. .)
Impostare
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;
Interrogazione 1 collegamento "Incolla il piano"
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;
Interrogazione 2 collegamento "Incolla il piano"
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;
Query 1
Query 2
Quanto sopra è stato testato su SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64)
@Joe Obbish sottolinea nei commenti che sarebbe una riproduzione più semplice
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;
Per la tabella di gestione temporanea a 1.000 righe, entrambe le precedenti hanno ancora la stessa forma di piano con loop nidificati e il piano senza la tabella derivata appare più economico, ma per una tabella di gestione temporanea a 10.000 righe e la stessa tabella di destinazione sopra, la differenza di costi modifica il piano la forma (con una scansione completa e unisci unione che sembra relativamente più attraente di ricerche a costo elevato) che mostra questa discrepanza di costo può avere implicazioni oltre a rendere più difficile il confronto dei piani.