Какие факторы стоимости входят в оптимизатор при выборе различных типов катушек?

15

Spoolum

В SQL Server есть несколько видов катушек. Меня интересуют две из них: Table Spool s и Index Spoo , за исключением запросов на изменение .

Запросы «только для чтения», особенно на внутренней стороне объединения с вложенными циклами, могут использовать катушку таблиц или индексов, чтобы потенциально сократить число операций ввода-вывода и повысить производительность запросов. Эти катушки могут быть нетерпеливыми или ленивыми . Так же, как вы и я.

Мои вопросы:

  • Какие факторы влияют на выбор таблицы против индекса
  • Какие факторы влияют на выбор между Eager и Lazy Spools
Эрик Дарлинг
источник

Ответы:

12

Это немного обширно, но я думаю, что понимаю Истинный Вопрос и отвечу соответственно. Просто собираюсь поговорить о таблице против индекса спула, хотя. Я не думаю, что это правильно, если рассматривать выбор между таблицами и катушками индексов. Как вы знаете, в одном поддереве можно получить катушку индекса, катушку таблицы или и катушку индекса, и катушку таблицы. Я считаю, что в целом правильно сказать, что вы получаете катушку индекса при следующих условиях:

  1. У оптимизатора запросов есть причина для преобразования объединения в заявку
  2. Оптимизатор запросов фактически выполняет преобразование для применения
  3. Оптимизатор запросов использует правило для добавления катушки индекса (как минимум, катушка индекса должна быть безопасной для использования)
  4. План с индексом спул выбран

Вы можете увидеть большинство из них с помощью простых демонстраций. Начните с создания пары кучи:

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подсказкой запроса:

введите описание изображения здесь

Это не полный ответ, но, надеюсь, это то, что вы искали.

Джо Оббиш
источник