Sto ponendo questa domanda al fine di comprendere meglio il comportamento dell'ottimizzatore e comprendere i limiti relativi agli spool degli indici. Supponiamo che io metta numeri interi da 1 a 10000 in un heap:
CREATE TABLE X_10000 (ID INT NOT NULL);
truncate table X_10000;
INSERT INTO X_10000 WITH (TABLOCK)
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
E forzare un loop nidificato con MAXDOP 1
:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Questa è un'azione piuttosto ostile da intraprendere verso SQL Server. I join di loop nidificati spesso non sono una buona scelta quando entrambe le tabelle non hanno indici rilevanti. Ecco il piano:
La query impiega 13 secondi sulla mia macchina con 100000000 righe recuperate dallo spool della tabella. Tuttavia, non vedo perché la query debba essere lenta. Query Optimizer ha la capacità di creare indici al volo tramite spool di indice . Questa query sembra essere un candidato perfetto per uno spool di indice.
La query seguente restituisce gli stessi risultati della prima, ha uno spool di indice e termina in meno di un secondo:
SELECT *
FROM X_10000 a
CROSS APPLY (SELECT TOP (9223372036854775807) b.ID FROM X_10000 b WHERE a.ID = b.ID) ca
OPTION (LOOP JOIN, MAXDOP 1);
Questa query ha anche uno spool di indice e termina in meno di un secondo:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Perché la query originale non ha uno spool di indice? Esiste un insieme di suggerimenti documentati o non documentati o flag di traccia che gli daranno uno spool di indice? Ho trovato questa domanda correlata , ma non risponde completamente alla mia domanda e non riesco a far funzionare il misterioso flag di traccia per questa query.