Відсутній некластеризований індекс вже є частиною індексу кластеру


9

Я налагоджую повільно запущений запит, і в плані виконання пропонується некластеризований індекс із впливом 51.6648. Однак некластеризований індекс включає лише стовпці, які вже знаходяться у складеному кластерному індексі первинного ключа (ПК).

Це може бути через порядок стовпців в індексі? тобто, якщо стовпці в кластерному індексі не в порядку від найбільш селективного до найменшого, чи є потенціал для некластеризованого індексу для підвищення продуктивності?

Крім того, некластеризований індекс містить лише два з трьох стовпців ПК, а третій додається як доданий стовпець. Чи є includeще однією причиною, чому використання некластеризованого індексу може бути більш оптимальним?

Нижче наводиться приклад структур таблиць, з якими я працюю:

Столи-

Retailers (
    RetailerID int PK, 
    name ...)

Retailer_Relation_Types (
    RelationType smallint PK, 
    Description nvarchar(50) ...)

Retailer_Relations (
    RetailerID int PK FK, 
    RelatedRetailerID int PK FK, 
    RelationType smallint PK FK, 
    CreatedOn datetime ...)

У таблиці Retailer_Relationsє наступний складений індекс ПК та запропонований індекс-

CONSTRAINT PK_Retailer_Relations 
PRIMARY KEY CLUSTERED (
    RetailerID ASC, 
    RelatedRetailerID ASC, 
    RelationType ASC
    ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX <NameOfIndex> 
ON Retailer_Relations (
    RetailerID, 
    RelationType
    ) 
INCLUDE (
    RelatedRetailerID
    )

Відповіді:


12

У таблиці Retailer_Relations є наступний складений індекс ПК та запропонований індекс-

Хоча пропущені індекси можуть бути корисними і, безумовно, можуть працювати, я б не витрачав занадто багато часу на відсутні індекси, ці підказки створюються на оціночному плані виконання, а не на фактичному плані виконання.

Точніше, ці підказки засновані на передумові зниження вартості Query Bucks ™, що використовується операторами в плані. Оптимізатор обчислює розрахункові витрати та додає відповідні підказки про відсутність.

В результаті вони можуть помилитися. Якщо ви не впевнені, чи збираєтеся допомогти, найкраще - перевірити ситуацію до і після. Ви можете зробити це, додавши заяву SET STATISTICS IO, TIME ON;перед запуском запиту.

Крім того, ви можете використовувати статистичний аналізатор, щоб полегшити читання цих статистичних даних.

Це може бути через порядок стовпців в індексі?

Це правильно, створення відсутніх індексів може покращити вибірковість запитів, наприклад, якщо ваш запит виглядає так:

SELECT  RelatedRetailerID
FROM Retailer_Relations 
WHERE
RetailerID = 5 AND
RelationType = 20;

або так:

SELECT  RelatedRetailerID
FROM Retailer_Relations 
ORDER BY
RetailerID,
RelationType;

Причина цього полягає в тому, що обидва індекси можуть шукати в RetailerID, і ця частина не збирається змінюватися. Але що робити, якщо на RelationType застосовані додаткові фільтри / замовлення? Це було б повсюдно в кластерному індексі, внаслідок чого воно було б третім ключовим значенням, а не другим ключовим значенням. І як ми знаємо, це є другим ключовим значенням у NCI.

Гаразд, але коли або як некластеризований індекс покращить запит?

Кілька випадків можуть бути:

  • Якщо відношення типу фільтрує багато значень, залишковий введення / виведення може бути високим, що призводить до можливої ​​потреби в некластеризованому індексі (запит №1)
  • Впорядкування в двох стовпцях відбувається (Один спосіб), а набір результатів великий (Запит №2).
  • Як зазначав @AaronBertrand: якщо різниця розмірів CI порівняно з NCI становить значну кількість, додавання NCI зменшить кількість прочитаних сторінок за запитами, які користуються нею.

Примітка стороні NCI

В якості додаткового зауваження, додавання стовпців клавіш до списку включення у вашій NCI точно не потрібно, оскільки стовпці ключів CI автоматично включаються до всіх некластеризованих індексів.

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

Що стосується самого запиту, якщо ви додали план виконання через PasteThePlan, ми могли б дати трохи більше інформації про індексацію / покращення запиту.


Тестування

Створіть таблицю і додайте кілька рядків

CREATE TABLE Retailer_Relations (
    RetailerID int , 
    RelatedRetailerID int , 
    RelationType smallint, 
    CreatedOn datetime,
    CONSTRAINT PK_Retailer_Relations 
PRIMARY KEY CLUSTERED (
    RetailerID ASC, 
    RelatedRetailerID ASC, 
    RelationType ASC
    ) ON [PRIMARY])


    DECLARE @I Int = 1
    WHILE @I < 1000
    BEGIN
    INSERT INTO Retailer_Relations(RetailerID,RelatedRetailerID,RelationType,CreatedOn)
    VALUES(@I,@I,@I,GETDATE()
    )
    set @I += 1
    END

Запит №1

    SELECT  RelatedRetailerID
FROM Retailer_Relations 
WHERE
RetailerID = 5 AND
RelationType = 20;

План без індексу Тут

Поки він робить пошук, він робить пошук на RetailerID. Після цього він видає залишковий предикат вводу / виводу на RelationType

Додайте індекс

CREATE NONCLUSTERED INDEX IX_TEST
ON Retailer_Relations (
    RetailerID, 
    RelationType
    ) 
INCLUDE (
    RelatedRetailerID
    )

Залишковий предикат зник, усе відбувається в предикаті пошуку в обох стовпцях.

План виконання

З другим запитом додана допоміжна індекс стає ще більш очевидною:

SELECT  RelatedRetailerID
FROM Retailer_Relations 
ORDER BY
RetailerID,
RelationType;

Плануйте без індексу з оператором Сортування:

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

Плануйте за допомогою індексу, за допомогою індексу видаляється оператор сортування

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


1
Дякую Ранді, я позначу це як відповідь, але просто хотів би запитати, ти кажеш, що пропозиція про відсутність індексу базується на оціночному плані виконання? Я запитую це, як це відображено в Фактичному плані виконання у SS2016.
Флетч

1
Мені було цікаво, чи це ви сказали, дякую за уточнення.
Флетч
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.