Как я могу исключить оператор Key Lookup (Clustered) в моем плане выполнения?
Таблица tblQuotes
уже имеет кластеризованный индекс (on QuoteID
) и 27 некластеризованных индексов, поэтому я стараюсь больше не создавать.
Я поместил столбец кластеризованного индекса QuoteID
в свой запрос, надеясь, что это поможет, но, к сожалению, все так же
Или просмотрите это:
Вот что говорит оператор поиска ключей:
Запрос:
declare
@EffDateFrom datetime ='2017-02-01',
@EffDateTo datetime ='2017-08-28'
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IF OBJECT_ID('tempdb..#Data') IS NOT NULL
DROP TABLE #Data
CREATE TABLE #Data
(
QuoteID int NOT NULL, --clustered index
[EffectiveDate] [datetime] NULL, --not indexed
[Submitted] [int] NULL,
[Quoted] [int] NULL,
[Bound] [int] NULL,
[Exonerated] [int] NULL,
[ProducerLocationId] [int] NULL,
[ProducerName] [varchar](300) NULL,
[BusinessType] [varchar](50) NULL,
[DisplayStatus] [varchar](50) NULL,
[Agent] [varchar] (50) NULL,
[ProducerContactGuid] uniqueidentifier NULL
)
INSERT INTO #Data
SELECT
tblQuotes.QuoteID,
tblQuotes.EffectiveDate,
CASE WHEN lstQuoteStatus.QuoteStatusID >= 1 THEN 1 ELSE 0 END AS Submitted,
CASE WHEN lstQuoteStatus.QuoteStatusID = 2 or lstQuoteStatus.QuoteStatusID = 3 or lstQuoteStatus.QuoteStatusID = 202 THEN 1 ELSE 0 END AS Quoted,
CASE WHEN lstQuoteStatus.Bound = 1 THEN 1 ELSE 0 END AS Bound,
CASE WHEN lstQuoteStatus.QuoteStatusID = 3 THEN 1 ELSE 0 END AS Exonareted,
tblQuotes.ProducerLocationID,
P.Name + ' / '+ P.City as [ProducerName],
CASE WHEN tblQuotes.PolicyTypeID = 1 THEN 'New Business'
WHEN tblQuotes.PolicyTypeID = 3 THEN 'Rewrite'
END AS BusinessType,
tblQuotes.DisplayStatus,
tblProducerContacts.FName +' '+ tblProducerContacts.LName as Agent,
tblProducerContacts.ProducerContactGUID
FROM tblQuotes
INNER JOIN lstQuoteStatus
on tblQuotes.QuoteStatusID=lstQuoteStatus.QuoteStatusID
INNER JOIN tblProducerLocations P
On P.ProducerLocationID=tblQuotes.ProducerLocationID
INNER JOIN tblProducerContacts
ON dbo.tblQuotes.ProducerContactGuid = tblProducerContacts.ProducerContactGUID
WHERE DATEDIFF(D,@EffDateFrom,tblQuotes.EffectiveDate)>=0 AND DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <=0
AND dbo.tblQuotes.LineGUID = '6E00868B-FFC3-4CA0-876F-CC258F1ED22D'--Surety
AND tblQuotes.OriginalQuoteGUID is null
select * from #Data
План выполнения:
Ответы:
Поиск ключей различных типов происходит, когда обработчику запросов необходимо получить значения из столбцов, которые не хранятся в индексе, используемом для поиска строк, необходимых для запроса, чтобы возвратить результаты.
Возьмем, к примеру, следующий код, где мы создаем таблицу с одним индексом:
Мы вставим 1 000 000 строк в таблицу, чтобы у нас были данные для работы:
Теперь мы запросим данные с возможностью отображения «фактического» плана выполнения:
План запроса показывает:
Запрос просматривает
IX_Table1
индекс, чтобы найти строку,Table1ID = 5000000
так как просмотр этого индекса выполняется намного быстрее, чем сканирование всей таблицы в поисках этого значения. Однако для удовлетворения результатов запроса обработчик запросов также должен найти значение для других столбцов в таблице; это - то, где «Поиск RID» входит. Он ищет в таблице идентификатор строки (RID в поиске RID), связанный со строкой, содержащейTable1ID
значение 500000, получая значения изTable1Data
столбца. Если навести указатель мыши на узел «RID Lookup» в плане, вы увидите следующее:«Список вывода» содержит столбцы, возвращаемые поиском RID.
Таблица с кластеризованным индексом и некластеризованным индексом является интересным примером. Таблица ниже имеет три столбца; Идентификатор, который является ключом кластеризации,
Dat
который индексируется некластеризованным индексомIX_Table
и третьим столбцомOth
.Возьмите этот пример запроса:
Мы просим SQL Server вернуть каждый столбец из таблицы, где
Dat
столбец содержит словоTest
. У нас есть несколько вариантов здесь; мы можем посмотреть на таблицу (т. е. на кластерный индекс) - но это повлечет за собой сканирование всей вещи, поскольку таблица упорядочена поID
столбцу, что ничего не говорит о том, какие строки содержатсяTest
вDat
столбце. Другой вариант (и тот, который выбран SQL Server) состоит в поискеIX_Table1
некластеризованного индекса, чтобы найти строку, гдеDat = 'Test'
, однако, поскольку нам также нуженOth
столбец, SQL Server должен выполнить поиск в кластеризованном индексе с помощью «ключа». Поиск "операция. Это план для этого:Если мы изменяем не-кластерный индекс , так что она включает в
Oth
столбец:Затем повторите запрос:
Теперь мы видим один некластеризованный поиск индекса, поскольку SQL Server просто нужно найти строку
Dat = 'Test'
вIX_Table1
индексе, которая включает в себя значение дляOth
и значение дляID
столбца (первичный ключ), который автоматически присутствует в каждом кластерный индекс. План:источник
Поиск ключа вызван тем, что движок решил использовать индекс, который содержит не все столбцы, которые вы пытаетесь получить. Таким образом, индекс не охватывает столбцы в операторе select и where.
Чтобы исключить поиск ключа, необходимо включить отсутствующие столбцы (столбцы в списке «Вывод ключа») = ProducerContactGuid, QuoteStatusID, PolicyTypeID и ProducerLocationID или другим способом заставить запрос использовать вместо этого кластеризованный индекс.
Обратите внимание, что 27 некластеризованные индексы в таблице могут ухудшить производительность. При запуске обновления, вставки или удаления SQL Server должен обновить все индексы. Эта дополнительная работа может негативно повлиять на производительность.
источник
Вы забыли упомянуть объем данных, связанных с этим запросом. Кроме того, почему вы вставляете в временную таблицу? Если вам нужно только отобразить, не запускайте оператор вставки.
Для целей этого запроса
tblQuotes
не нужно 27 некластеризованных индексов. Для этого требуется 1 кластеризованный индекс и 5 некластеризованных индексов или, возможно, 6 некластеризованных индексов.Этот запрос хотел бы индексы для этих столбцов:
Я также заметил следующий код:
является
NON Sargable
то , что не может использовать индексы.Чтобы заставить этот код
SARgable
изменить это на это:Чтобы ответить на ваш главный вопрос, «почему вы получаете ключ, посмотрите вверх»:
Вы получаете,
KEY Look up
потому что некоторые из столбцов, которые упоминаются в запросе, отсутствуют в покрывающем индексе.Вы можете гуглить и изучать
Covering Index
илиInclude index
.В моем примере предположим, что tblQuotes.QuoteStatusID является некластеризованным индексом, тогда я также могу покрыть DisplayStatus. Так как вы хотите DisplayStatus в Resultset. Любой столбец, который отсутствует в индексе и присутствует в наборе результатов, может быть закрыт, чтобы избежать
KEY Look Up or Bookmark lookup
. Это пример покрывающего индекса:** Отказ от ответственности: ** Помните, что выше - только мой пример. DisplayStatus может быть покрыт другими Non CI после анализа.
Точно так же вам придется создать индекс и индекс покрытия для других таблиц, участвующих в запросе.
Вы получаете
Index SCAN
также в своем плане.Это может произойти из-за отсутствия индекса в таблице или из-за большого объема данных, который оптимизатор может решить сканировать, а не выполнять поиск по индексу.
Это также может произойти из-за
High cardinality
. Получение большего количества строк, чем требуется из-за неправильного соединения. Это также можно исправить.источник