Це трохи широко, але я думаю, що я розумію Справжнє запитання і відповім відповідно. Просто поговоримо про таблицю проти індексної котушки. Я не думаю, що це цілком коректно сприймати там як вибір між таблицею та індексними котушками. Як відомо, в одному піддереві можна отримати індексну котушку, столову котушку або і індексну котушку, і табличну котушку. Я вважаю, що як правило, правильно сказати, що ви отримуєте індексну котушку за таких умов:
- Оптимізатор запитів має підставу перетворити приєднання у додаток
- Оптимізатор запитів фактично виконує перетворення в застосунок
- Оптимізатор запитів використовує правило для додавання котушки індексу (як мінімум, котушка індексу повинна бути безпечною для використання)
- Вибирається план із вказівною котушкою
Більшість із них можна побачити за допомогою простих демонстрацій. Почніть зі створення пари купи:
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
підказкою щодо недокументованого запиту:
Це не повна відповідь, але, сподіваємось, це частина того, що ви шукали.