Como posso eliminar um operador Key Lookup (Clustered) em meu plano de execução?
A tabela tblQuotes
já tem um índice clusterizado (on QuoteID
) e 27 índices não clusterizados, então estou tentando não criar mais.
Coloquei a coluna de índice clusterizado QuoteID
na minha consulta, esperando que ajude - mas infelizmente ainda é o mesmo.
Ou veja:
Isto é o que o operador Key Lookup diz:
Consulta:
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
Plano de execução:
Pesquisas de chave de vários tipos ocorrem quando o processador de consulta precisa obter valores de colunas que não estão armazenadas no índice usado para localizar as linhas necessárias para a consulta retornar resultados.
Tomemos como exemplo o código a seguir, onde estamos criando uma tabela com um único índice:
Vamos inserir 1.000.000 de linhas na tabela para que tenhamos alguns dados para trabalhar:
Agora, consultaremos os dados com a opção de exibir o plano de execução "real":
O plano de consulta mostra:
A consulta examina o
IX_Table1
índice para localizar a linha,Table1ID = 5000000
pois examinar esse índice é muito mais rápido do que examinar a tabela inteira procurando esse valor. No entanto, para satisfazer os resultados da consulta, o processador de consulta também deve localizar o valor das outras colunas da tabela; é aí que entra o "RID Lookup". Ele procura na tabela o ID da linha (o RID em RID Lookup) associado à linha que contém oTable1ID
valor 500000, obtendo os valores daTable1Data
coluna. Se você passar o mouse sobre o nó "RID Lookup" no plano, verá isto:A "Lista de Saída" contém as colunas retornadas pela Pesquisa RID.
Uma tabela com um índice clusterizado e um índice não clusterizado é um exemplo interessante. A tabela abaixo tem três colunas; ID que é a chave de cluster,
Dat
que é indexada por um índice não clusterizadoIX_Table
e uma terceira coluna,Oth
.Veja este exemplo de consulta:
We're asking SQL Server to return every column from the table where the
Dat
column contains the wordTest
. We have a couple of choices here; we can look at the table (i.e. the clustered index) - but that would entail scanning the entire thing since the table is ordered by theID
column, which tells us nothing about which row(s) containTest
in theDat
column. The other option (and the one chosen by SQL Server) consists of seeking into theIX_Table1
non-clustered index to find the row whereDat = 'Test'
, however since we need theOth
column as well, SQL Server must perform a lookup into the clustered index using a "Key Lookup" operation. This is the plan for that:If we modify the non-clustered index so that it includes the
Oth
column:Em seguida, execute novamente a consulta:
Agora vemos uma única busca de índice não clusterizado, pois o SQL Server simplesmente precisa localizar a linha onde
Dat = 'Test'
noIX_Table1
índice, que inclui o valor deOth
, e o valor daID
coluna (a chave primária), que está automaticamente presente em todos os dados não-agrupados. índice agrupado. O plano:A pesquisa de chave é causada porque o mecanismo optou por usar um índice que não contém todas as colunas que você está tentando buscar. Portanto, o índice não está cobrindo as colunas na instrução select e where.
Para eliminar a pesquisa de chave, você precisa incluir as colunas ausentes (as colunas na lista de saída da pesquisa de chave) = ProducerContactGuid, QuoteStatusID, PolicyTypeID e ProducerLocationID ou outra maneira é forçar a consulta a usar o índice clusterizado.
Observe que 27 índices não clusterizados em uma tabela podem ser ruins para o desempenho. Ao executar uma atualização, inserção ou exclusão, o SQL Server deve atualizar todos os índices. Este trabalho extra pode afetar negativamente o desempenho.
Você esqueceu de mencionar o volume de dados envolvidos nesta consulta. Além disso, por que você está inserindo em uma tabela temporária? Se apenas você precisar exibir, não execute uma instrução de inserção.
Para os fins desta consulta,
tblQuotes
não são necessários 27 índices não clusterizados. Ele precisa de 1 índice clusterizado e 5 índices não clusterizados ou, talvez, 6 indexex não clusterizados.Esta consulta gostaria de índices nestas colunas:
Notei também o seguinte código:
é
NON Sargable
ou seja, não pode utilizar índices.Para fazer esse código
SARgable
alterá-lo para isso:Para responder à sua pergunta principal, "por que você está recebendo uma chave Look up":
Você está recebendo
KEY Look up
porque algumas das colunas mencionadas na consulta não estão presentes em um índice de cobertura.Você pode pesquisar no Google e estudar sobre
Covering Index
ouInclude index
.No meu exemplo, suponha que tblQuotes.QuoteStatusID é índice não clusterizado, então também posso cobrir DisplayStatus. Desde que você queira DisplayStatus em Resultset. Qualquer coluna que não esteja presente em um índice e esteja presente no conjunto de resultados pode ser coberta para evitar
KEY Look Up or Bookmark lookup
. Este é um exemplo de índice de cobertura:**Isenção de responsabilidade:**Lembre-se acima é apenas meu exemplo DisplayStatus pode ser coberto com outro não CI após a análise.
Da mesma forma, você terá que criar índice e índice de cobertura nas outras tabelas envolvidas na consulta.
Você
Index SCAN
também está entrando no seu plano.Isso pode acontecer porque não há índice na tabela ou quando há um grande volume de dados, o otimizador pode decidir varrer em vez de realizar uma busca de índice.
Isso também pode ocorrer devido a
High cardinality
. Obtendo mais número de linhas do que o necessário devido a uma junção defeituosa. Isso também pode ser corrigido.