Таблица Retailer_Relations имеет следующий составной индекс PK и предлагаемый индекс-
Хотя отсутствующие индексы могут быть полезными и определенно работать, я бы не стал тратить слишком много времени на отсутствующие индексы, эти подсказки создаются на приблизительном плане выполнения, а не на фактическом плане выполнения.
Точнее, эти подсказки индекса основаны на предпосылке снижения стоимости Query Bucks ™, используемых операторами в плане. Оптимизатор вычисляет предполагаемые затраты и соответственно добавляет недостающие подсказки индекса.
В результате они могут быть очень неправы. Если вы не уверены, поможет ли это, лучше всего проверить ситуацию до и после. Вы можете сделать это, добавив оператор
SET STATISTICS IO, TIME ON;
перед выполнением запроса.
Кроме того, вы можете использовать statisticsparser, чтобы упростить чтение этой статистики.
Может ли это быть из-за порядка столбцов в индексе?
Это правильно, создание отсутствующего индекса может улучшить селективность запросов, например, если ваш запрос выглядит следующим образом:
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;
План без индекса, с оператором сортировки:
План с индексом, с помощью индекса удаляется оператор сортировки