Это немного обширно, но я думаю, что понимаю Истинный Вопрос и отвечу соответственно. Просто собираюсь поговорить о таблице против индекса спула, хотя. Я не думаю, что это правильно, если рассматривать выбор между таблицами и катушками индексов. Как вы знаете, в одном поддереве можно получить катушку индекса, катушку таблицы или и катушку индекса, и катушку таблицы. Я считаю, что в целом правильно сказать, что вы получаете катушку индекса при следующих условиях:
- У оптимизатора запросов есть причина для преобразования объединения в заявку
- Оптимизатор запросов фактически выполняет преобразование для применения
- Оптимизатор запросов использует правило для добавления катушки индекса (как минимум, катушка индекса должна быть безопасной для использования)
- План с индексом спул выбран
Вы можете увидеть большинство из них с помощью простых демонстраций. Начните с создания пары кучи:
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
По первому запросу искать нечего:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);
Поэтому у оптимизатора нет причин превращать объединение в заявку. В результате вы получаете катушку из-за стоимости. Таким образом, этот запрос не проходит первый тест.
Для следующего запроса справедливо ожидать, что у оптимизатора есть причина рассмотреть применение:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Но это не значит:
Этот запрос не проходит второй тест. Полное объяснение здесь . Цитируем наиболее актуальную часть:
Оптимизатор не рассматривает возможность создания индекса на лету, чтобы разрешить применение; скорее последовательность событий, как правило, обратная: преобразуйте, чтобы применить, потому что существует хороший индекс.
Я могу переписать запрос, чтобы оптимизатор рассмотрел применение:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);
Но все еще нет катушки индекса:
Этот запрос не проходит третий тест. В SQL Server 2014 было ограничение длины ключа индекса в 900 байтов. Это было расширено в SQL Server 2016, но только для некластеризованных индексов. Индекс для буфера является кластеризованным, поэтому ограничение остается на уровне 900 байтов . В любом случае правило спулинга индекса не может быть применено, поскольку оно может привести к ошибке во время выполнения запроса.
Сокращение длины типа данных до 800 наконец дает плану с катушкой индекса:
Не удивительно, что план катушки индекса стоит значительно дешевле, чем план без катушки: 89,7603 единиц против 598,832 единиц. Вы можете увидеть разницу с недокументированной QUERYRULEOFF BuildSpool
подсказкой запроса:
Это не полный ответ, но, надеюсь, это то, что вы искали.