Próbuję zrozumieć, dlaczego użycie zmiennej tabeli uniemożliwia optymalizatorowi korzystanie z wyszukiwania indeksu, a następnie wyszukiwania zakładek w porównaniu ze skanowaniem indeksu.
Wypełnianie tabeli:
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)
Wypełnij zmienną tabeli jednym rekordem i spróbuj wyszukać klucz podstawowy i drugą kolumnę, wyszukując kolumnę klucza obcego:
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
Poniżej znajduje się plan wykonania:
Teraz to samo zapytanie przy użyciu tabeli tymczasowej:
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
W tym planie zapytań zastosowano wyszukiwanie i wyszukiwanie zakładek:
Dlaczego optymalizator chce wyszukiwać zakładki z tabelą tymczasową, ale nie ze zmienną tabelową?
Zmienna tabeli jest używana w tym przykładzie do reprezentowania danych przechodzących przez typ tabeli zdefiniowanej przez użytkownika w procedurze składowanej.
Zdaję sobie sprawę, że wyszukiwanie indeksu może nie być odpowiednie, jeśli wartość klucza obcego wystąpiłaby setki tysięcy razy. W takim przypadku skan byłby prawdopodobnie lepszym wyborem. W stworzonym przeze mnie scenariuszu nie było wiersza o wartości 10. Nadal uważam, że zachowanie jest interesujące i chciałbym wiedzieć, czy istnieje ku temu powód.
Dodanie OPTION (RECOMPILE)
nie zmieniło zachowania. UDDT ma klucz podstawowy.
@@VERSION
to SQL Server 2008 R2 (SP2) - 10.50.4042.0 (X64) (kompilacja 7601: Service Pack 1) (Hypervisor)