Давайте разберем проблему, а затем обсудим решения для ее улучшения:
У вас есть таблица (назовем ее tblTest1
и содержит 2М записей) с кластеризованным индексом на id
и неКластерный индекс на t_id
, и вы собираетесь запросить данные, которые фильтруют данные, используя некластерный индекс и получить столбцы id
и num
.
Таким образом, сервер SQL будет использовать некластерный индексдля фильтрации данных (t_id=587
), но после фильтрации данных SQL-серверу необходимо получить значения, хранящиеся в столбцах id
и num
.Очевидно, поскольку у вас есть кластеризованный индекс, SQL-сервер будет использовать этот индекс для получения данных, хранящихся в столбцах id
и num
.Это происходит потому, что листы в дереве некластеризованного индекса содержат значение кластерного индекса, поэтому вы видите оператор Key Lookup в плане выполнения.Фактически SQL Server использует Index seek(NonCluster)
для поиска t_id=587
, а затем использует Key Lookup
для получения данных num
! (SQL Server не будет использовать этот оператор для получения значения, хранящегося в столбце id
, посколькуу вас есть кластеризованный индекс, а листы в некластеризованном индексе содержат значение кластерного индекса).
![enter image description here](https://i.stack.imgur.com/vCw7d.png)
Обратимся к вышеупомянутому снимку экрана, когда мыIndex Seek(NonClustred)
и Key Lookup
, SQL Server требуется оператор Nested Loop Join
для получения данных в столбце num
с помощью оператора Index Seek(Nonclustered)
.Фактически на этом этапе SQL Server имеет два отдельных набора: один - это результаты, полученные из дерева некластеризованного индекса, а другой - данные внутри дерева кластерного индекса.
Исходя из этой истории, проблема ясна!Что произойдет, если мы скажем SQL-серверу не выполнять поиск ключей?это приведет к тому, что SQL Server выполнит запрос более коротким способом (нет необходимости в поиске ключей и, очевидно, нет необходимости в присоединении к вложенному циклу!).
Для этого нам нужно INCLUDE
столбец num
внутри дерева некластеризованного индекса, поэтому в этом случае лист этого индекса будет содержать данные столбца id
, а также num
данные столбца!Ясно, что когда мы говорим SQL Server найти данные с использованием NonClustred Index и вернуть столбцы id
и num
, ему не нужно выполнять поиск ключей!
Наконец, нам нужно сделать следующее:INCLUDE
num
в некластеризованном индексе!Благодаря @ MJH ответу:
CREATE NONCLUSTERED INDEX idx ON tblTest1 (t_id)
INCLUDE (num)
![enter image description here](https://i.stack.imgur.com/K9Sno.png)
К счастью, SQL Server 2005 предоставил новую функцию для некластеризованных индексоввозможность включения дополнительных неключевых столбцов на конечный уровень некластеризованных индексов!
Подробнее:
https://www.red -gate.com / simple-talk /sql / learn-sql-сервер / использование-покрытия-индексов-для-улучшения-производительности запросов /
https://docs.microsoft.com/en-us/sql/relational-databases/indexes/create-indexes-with-included-columns?view=sql-server-2017
Но что произойдет, если мы напишем запрос какэто?
SELECT id, num
FROM tblTest1 AS t1
WHERE
EXISTS (SELECT 1
FROM tblTest1 t2
WHERE t2.t_id = 587 AND t2.id = t1.id
)
Это отличный подход, но давайте посмотрим план выполнения:
![enter image description here](https://i.stack.imgur.com/5skbS.png)
Очевидно, что SQL-сервер нуждаетсявыполнить поиск по индексу (NonClustered), чтобы найти t_id = 587, а затем получить данные из Clustered Index с помощью поиска Clustered Index Seek.В этом случае мы не получим заметного улучшения производительности.
Примечание: Когда вы используете индексы, вам нужен соответствующий план для их обслуживания.По мере фрагментации индексов их влияние на производительность запросов будет уменьшаться, и через некоторое время у вас могут возникнуть проблемы с производительностью!У вас должен быть соответствующий план их реорганизации и восстановления, когда они фрагментированы!
Подробнее: https://docs.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes?view=sql-server-2017