Я задаю этот вопрос, чтобы лучше понять поведение оптимизатора и понять ограничения вокруг катушек индекса. Предположим, что я положил целые числа от 1 до 10000 в кучу:
CREATE TABLE X_10000 (ID INT NOT NULL);
truncate table X_10000;
INSERT INTO X_10000 WITH (TABLOCK)
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
И принудительно включите вложенный цикл MAXDOP 1
:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Это довольно недружественное действие по отношению к SQL Server. Соединения с вложенными циклами часто не являются хорошим выбором, когда обе таблицы не имеют соответствующих индексов. Вот план:
Запрос занимает 13 секунд на моей машине с 100000000 строк, извлеченных из буфера таблицы. Однако я не понимаю, почему запрос должен быть медленным. Оптимизатор запросов имеет возможность создавать индексы на лету с помощью катушек индексов . Этот запрос выглядит как идеальный кандидат на катушку индекса.
Следующий запрос возвращает те же результаты, что и первый, имеет катушку индекса и завершается менее чем за секунду:
SELECT *
FROM X_10000 a
CROSS APPLY (SELECT TOP (9223372036854775807) b.ID FROM X_10000 b WHERE a.ID = b.ID) ca
OPTION (LOOP JOIN, MAXDOP 1);
Этот запрос также имеет катушку индекса и завершается менее чем за секунду:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Почему исходный запрос не имеет катушку индекса? Существует ли какой-либо набор документированных или недокументированных подсказок или флагов трассировки, которые дадут ему катушку индекса? Я нашел этот связанный вопрос , но он не полностью отвечает на мой вопрос, и я не могу заставить загадочный флаг трассировки работать для этого запроса.