Почему переменная таблицы принудительная проверка индекса, когда таблица Temp использует поиск и закладки?
Вопрос
Я пытаюсь понять, почему использование переменной таблицы предотвращает использование оптимизатора с использованием поиска индекса, а затем Lookmark Lookup по сравнению с индексом.
Заполнение таблицы:
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
.
Ниже приведен план выполнения:
Теперь тот же запрос, используя таблицу TEMP:
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
.
Этот план запроса использует поиск и закладки:
Почему оптимизатор желает сделать поиск закладки с таблицей TEMP, но не переменная таблицы?
Переменная таблицы используется в этом примере для представления данных, проходящих через пользовательскую таблицу в хранимой процедуре.
Я понимаю, что поиск индекса может не подделать, если ценность внешнего ключа произошла сотни тысяч раз. В этом случае сканирование, вероятно, будет лучшим выбором. Для сценария я создал, не было никакого ряда со значением 10. Я все еще думаю, что поведение интересно и хотелось бы знать, есть ли причина для этого.
Добавление OPTION (RECOMPILE)
не изменил поведение. У UDDT имеет первичный ключ.
@@VERSION
- SQL Server 2008 R2 (SP2) - 10.50.4042.0 (x64) (Build 7601: Пакет обновления 1) (Hypervisor)
Решение
Причина поведения в том, что SQL Server не может определить, сколько строк будет соответствовать Инонневрей, поскольку нет индекса с rowkey, как ведущий столбец (он может вывести это из статистики на таблице #temp, но те Не существуйте для переменных / UDTTS таблицы), поэтому он делает оценку 100 000 строк, что лучше обрабатывается со сканированием, чем искать + поиск. К тому времени SQL Server понимает, что есть только одна строка, уже слишком поздно.
Вы можете построить свой UDTT по-другому; В более современных версиях SQL Server вы можете создавать дополнительные индексы на переменных таблиц, но этот синтаксис недоступен в 2008 году R2.
BTW Вы можете получить поведение искать (по крайней мере, в моих ограниченных испытаниях), если вы попытаетесь избежать растрового изображения / зонда, намекая вложенные петли, соединяйте:
DECLARE @Keys TABLE (RowKey INT PRIMARY KEY); -- can't hurt
INSERT @Keys (RowKey) VALUES (10);
SELECT
t.RowKey
,t.SecondColumn
FROM
dbo.Test t
INNER JOIN
@Keys k
ON
t.ForeignKey = k.RowKey
OPTION (LOOP JOIN);
.
i Узнал этот трюк из Пола Белым несколько лет назад. Конечно, вы должны быть осторожны о том, чтобы положить какие-либо подсказки в коде изготовления в производстве - это может потерпеть неудачу, если люди вступают в изменение в основные объекты, и этот конкретный тип присоединения больше не возможен или больше не является наиболее оптимальным.
Для более сложных запросов, и когда вы переходите на SQL Server 2012 или выше, возможно, что Флаг трассировки 2453 может помочь. Этот флаг не помог с этим простым присоединением, хотя. И одинаковые отказ от ответственности будут применяться - это просто альтернативное, что вы обычно не должны делать без тонны документации и строгих процедур тестирования регрессии.
Кроме того, пакет обновления 1 - давно не поддерживает, вы должны попасть на Пакет обновления 3 + ms15-058 .
Другие советы
Переменные таблицы и таблицы TEMP обрабатываются по-разному несколькими способами.Есть a GreatОтветьте здесь с большим количеством специфики, насколько они отличаются.
В частности, в вашем случае я догадаю, что тот факт, что TEMP Tables может иметь дополнительные сгенерированные статистики и параллельные планы, когда переменные таблицы имеют более ограниченную статистику (нет статистики уровня столбцов), и параллельные планы не являются вашим виновником.
Вам вполне может быть лучше, чтобы лучше сбрасывать переменную таблицу в таблицу TEMP на время сохраненной процедуры.