Я пытаюсь понять, почему использование табличной переменной не позволяет оптимизатору использовать поиск по индексу, а затем поиск по закладкам по сравнению со сканированием индекса.
Заполнение таблицы:
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)
Заполните табличную переменную одной записью и попытайтесь найти первичный ключ и второй столбец, выполнив поиск по столбцу внешнего ключа:
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
Ниже приведен план выполнения:
Теперь тот же запрос, используя вместо этого временную таблицу:
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
Этот план запроса использует поиск и поиск по закладкам:
Почему оптимизатор хочет выполнить поиск закладок с помощью временной таблицы, но не табличной переменной?
Переменная table используется в этом примере для представления данных, поступающих через определенный пользователем тип таблицы в хранимой процедуре.
Я понимаю, что поиск по индексу может быть неуместным, если значение внешнего ключа встречалось сотни тысяч раз. В этом случае, сканирование, вероятно, будет лучшим выбором. Для сценария, который я создал, не было строки со значением 10. Я все еще думаю, что поведение интересно, и хотел бы знать, есть ли причина для этого.
Добавление OPTION (RECOMPILE)
не изменило поведение. У UDDT есть первичный ключ.
@@VERSION
такое SQL Server 2008 R2 (SP2) - 10.50.4042.0 (X64) (сборка 7601: пакет обновления 1) (гипервизор)