Como posso eliminar um operador Key Lookup (Clustered) no meu plano de execução?
A tabela tblQuotes
já possui um índice clusterizado ( QuoteID
ativado) e 27 índices não clusterizados, portanto, estou tentando não criar mais.
Coloquei a coluna de índice clusterizado QuoteID
na minha consulta, esperando que isso ajude - mas infelizmente ainda é o mesmo.
Ou veja:
É o que o operador Key Lookup diz:
Inquerir:
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:
Respostas:
As principais pesquisas de vários tipos ocorrem quando o processador de consultas precisa obter valores de colunas que não são armazenadas no índice usado para localizar as linhas necessárias para a consulta retornar resultados.
Tomemos, por 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 termos alguns dados com os quais 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 encontrar a linha,Table1ID = 5000000
pois a análise desse índice é muito mais rápida do que a varredura de toda a tabela procurando esse valor. No entanto, para satisfazer os resultados da consulta, o processador de consultas também deve encontrar o valor para as outras colunas na tabela; é aqui que entra a "Pesquisa de RID". Ele procura na tabela o ID da linha (o RID na pesquisa de RID) associado à linha que contém oTable1ID
valor de 500000, obtendo os valores daTable1Data
coluna. Se você passar o mouse sobre o nó "Pesquisa de RID" no plano, verá o seguinte:A "Lista de saída" contém as colunas retornadas pela pesquisa do RID.
Uma tabela com um índice clusterizado e um índice não clusterizado é um exemplo interessante. A tabela abaixo possui três colunas; ID que é a chave de cluster,
Dat
que é indexada por um índice não em clusterIX_Table
e uma terceira colunaOth
.Pegue esta consulta de exemplo:
Pedimos ao SQL Server para retornar todas as colunas da tabela em que a
Dat
coluna contém a palavraTest
. Temos algumas opções aqui; podemos olhar para a tabela (ou seja, o índice clusterizado) - mas isso exigiria a varredura de toda a coisa, já que a tabela é ordenada pelaID
coluna, o que não nos diz nada sobre quais linhas contêmTest
naDat
coluna. A outra opção (e a escolhida pelo SQL Server) consiste em procurar noIX_Table1
índice não agrupado em cluster para encontrar a linha em queDat = 'Test'
, no entanto, como também precisamos daOth
coluna, o SQL Server deve executar uma pesquisa no índice agrupado usando uma "Chave Pesquisa ". Este é o plano para isso:Se modificarmos o índice não agrupado para que inclua a
Oth
coluna: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
Dat = 'Test'
em que lugar doIX_Table1
índice, que inclui o valor paraOth
e o valor daID
coluna (a chave primária), presente automaticamente em todos os índice agrupado. O plano:fonte
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, é necessário incluir as colunas ausentes (as colunas na lista 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 agrupados em uma tabela podem prejudicar o desempenho. Ao executar uma atualização, inserir ou excluir, o SQL Server deve atualizar todos os índices. Esse trabalho extra pode afetar negativamente o desempenho.
fonte
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 você precisar apenas exibir, não execute uma instrução de inserção.
Para os fins desta consulta,
tblQuotes
não é necessário 27 índices não agrupados em cluster. Ele precisa de 1 índice agrupado e 5 índices não agrupados ou, talvez, 6 índices não agrupados.Esta consulta gostaria de índices nessas colunas:
Também notei o seguinte código:
é
NON Sargable
ou seja, não pode utilizar índices.Para fazer esse código,
SARgable
mude para:Para responder à sua pergunta principal, "por que você está recebendo uma consulta importante":
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 é um índice não clusterizado, também posso cobrir o DisplayStatus. Desde que você deseja DisplayStatus no conjunto de resultados. 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 cobertura do índice:** Isenção de responsabilidade: ** Lembre-se de que acima é apenas meu exemplo que o DisplayStatus pode ser coberto com outros Não ICs após a análise.
Da mesma forma, você precisará criar um índice e um índice de cobertura nas outras tabelas envolvidas na consulta.
Você
Index SCAN
também está recebendo seu plano.Isso pode acontecer porque não há índice na tabela ou quando há um grande volume de dados que o otimizador pode decidir varrer em vez de executar 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 à associação incorreta. Isso também pode ser corrigido.fonte