Sto cercando di capire perché l'utilizzo di una variabile di tabella impedisce all'ottimizzatore di utilizzare una ricerca indice e quindi la ricerca dei segnalibri rispetto a una scansione dell'indice.
Popolazione della tabella:
CREATE TABLE dbo.Test
(
RowKey INT NOT NULL PRIMARY KEY,
SecondColumn CHAR(1) NOT NULL DEFAULT 'x',
ForeignKey INT NOT NULL
)
INSERT dbo.Test
(
RowKey,
ForeignKey
)
SELECT TOP 1000000
ROW_NUMBER() OVER (ORDER BY (SELECT 0)),
ABS(CHECKSUM(NEWID()) % 10)
FROM sys.all_objects s1
CROSS JOIN sys.all_objects s2
CREATE INDEX ix_Test_1 ON dbo.Test (ForeignKey)
Popolare una variabile di tabella con un singolo record e prova a cercare la chiave primaria e la seconda colonna cercando nella colonna chiave esterna:
DECLARE @Keys TABLE (RowKey INT NOT NULL)
INSERT @Keys (RowKey) VALUES (10)
SELECT
t.RowKey,
t.SecondColumn
FROM
dbo.Test t
INNER JOIN
@Keys k
ON
t.ForeignKey = k.RowKey
Di seguito è riportato il piano di esecuzione:
Ora invece la stessa query utilizzando una tabella temporanea:
CREATE TABLE #Keys (RowKey INT NOT NULL)
INSERT #Keys (RowKey) VALUES (10)
SELECT
t.RowKey,
t.SecondColumn
FROM
dbo.Test t
INNER JOIN
#Keys k
ON
t.ForeignKey = k.RowKey
Questo piano di query utilizza una ricerca di ricerca e segnalibro:
Perché l'ottimizzatore è disposto a cercare il segnalibro con la tabella temporanea, ma non con la variabile della tabella?
La variabile di tabella viene utilizzata in questo esempio per rappresentare i dati provenienti da un tipo di tabella definito dall'utente in una procedura memorizzata.
Mi rendo conto che la ricerca dell'indice potrebbe non essere appropriata se il valore della chiave esterna si verificava centinaia di migliaia di volte. In tal caso, una scansione sarebbe probabilmente una scelta migliore. Per lo scenario che ho creato, non vi era alcuna riga con un valore di 10. Penso ancora che il comportamento sia interessante e vorrei sapere se c'è una ragione per questo.
L'aggiunta OPTION (RECOMPILE)
non ha modificato il comportamento. L'UDDT ha una chiave primaria.
@@VERSION
è SQL Server 2008 R2 (SP2) - 10.50.4042.0 (X64) (Build 7601: Service Pack 1) (Hypervisor)