Почему переменная таблицы принудительная проверка индекса, когда таблица Temp использует поиск и закладки?

dba.stackexchange https://dba.stackexchange.com/questions/108352

Вопрос

Я пытаюсь понять, почему использование переменной таблицы предотвращает использование оптимизатора с использованием поиска индекса, а затем 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. Я все еще думаю, что поведение интересно и хотелось бы знать, есть ли причина для этого.

SQL Widdle

Добавление 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 на время сохраненной процедуры.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с dba.stackexchange
scroll top