AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 183006
Accepted
Serdia
Serdia
Asked: 2017-08-09 15:03:47 +0800 CST2017-08-09 15:03:47 +0800 CST 2017-08-09 15:03:47 +0800 CST

Elimine o operador Key Lookup (Clustered) que diminui o desempenho

  • 772

Como posso eliminar um operador Key Lookup (Clustered) em meu plano de execução?

A tabela tblQuotesjá 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 QuoteIDna minha consulta, esperando que ajude - mas infelizmente ainda é o mesmo.

Plano de execução aqui .

Ou veja:

insira a descrição da imagem aqui

Isto é o que o operador Key Lookup diz:

insira a descrição da imagem aqui

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:

insira a descrição da imagem aqui

sql-server sql-server-2012
  • 3 3 respostas
  • 43433 Views

3 respostas

  • Voted
  1. Best Answer
    Hannah Vernon
    2017-08-11T12:22:31+08:002017-08-11T12:22:31+08:00

    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:

    USE tempdb;
    
    IF OBJECT_ID(N'dbo.Table1', N'U') IS NOT NULL
    DROP TABLE dbo.Table1
    GO
    
    CREATE TABLE dbo.Table1
    (
        Table1ID int NOT NULL IDENTITY(1,1)
        , Table1Data nvarchar(30) NOT NULL
    );
    
    CREATE INDEX IX_Table1
    ON dbo.Table1 (Table1ID);
    GO
    

    Vamos inserir 1.000.000 de linhas na tabela para que tenhamos alguns dados para trabalhar:

    INSERT INTO dbo.Table1 (Table1Data)
    SELECT TOP(1000000) LEFT(c.name, 30)
    FROM sys.columns c
        CROSS JOIN sys.columns c1
        CROSS JOIN sys.columns c2;
    GO
    

    Agora, consultaremos os dados com a opção de exibir o plano de execução "real":

    SELECT *
    FROM dbo.Table1
    WHERE Table1ID = 500000;
    

    O plano de consulta mostra:

    insira a descrição da imagem aqui

    A consulta examina o IX_Table1índice para localizar a linha, Table1ID = 5000000pois 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 o Table1IDvalor 500000, obtendo os valores da Table1Datacoluna. Se você passar o mouse sobre o nó "RID Lookup" no plano, verá isto:

    insira a descrição da imagem aqui

    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, Datque é indexada por um índice não clusterizado IX_Tablee uma terceira coluna, Oth.

    USE tempdb;
    
    IF OBJECT_ID(N'dbo.Table1', N'U') IS NOT NULL
    DROP TABLE dbo.Table1
    GO
    
    CREATE TABLE dbo.Table1
    (
        ID int NOT NULL IDENTITY(1,1) 
            PRIMARY KEY CLUSTERED
        , Dat nvarchar(30) NOT NULL
        , Oth nvarchar(3) NOT NULL
    );
    
    CREATE INDEX IX_Table1
    ON dbo.Table1 (Dat);
    GO
    
    INSERT INTO dbo.Table1 (Dat, Oth)
    SELECT TOP(1000000) CRYPT_GEN_RANDOM(30), CRYPT_GEN_RANDOM(3)
    FROM sys.columns c
        CROSS JOIN sys.columns c1
        CROSS JOIN sys.columns c2;
    GO
    

    Veja este exemplo de consulta:

    SELECT *
    FROM dbo.Table1
    WHERE Dat = 'Test';
    

    We're asking SQL Server to return every column from the table where the Dat column contains the word Test. 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 the ID column, which tells us nothing about which row(s) contain Test in the Dat column. The other option (and the one chosen by SQL Server) consists of seeking into the IX_Table1 non-clustered index to find the row where Dat = 'Test', however since we need the Oth column as well, SQL Server must perform a lookup into the clustered index using a "Key Lookup" operation. This is the plan for that:

    insira a descrição da imagem aqui

    If we modify the non-clustered index so that it includes the Oth column:

    DROP INDEX IX_Table1
    ON dbo.Table1;
    GO
    
    CREATE INDEX IX_Table1
    ON dbo.Table1 (Dat)
    INCLUDE (Oth);        <---- This is the only change
    GO
    

    Em seguida, execute novamente a consulta:

    SELECT *
    FROM dbo.Table1
    WHERE Dat = 'Test';
    

    Agora vemos uma única busca de índice não clusterizado, pois o SQL Server simplesmente precisa localizar a linha onde Dat = 'Test'no IX_Table1índice, que inclui o valor de Oth, e o valor da IDcoluna (a chave primária), que está automaticamente presente em todos os dados não-agrupados. índice agrupado. O plano:

    insira a descrição da imagem aqui

    • 41
  2. Daniel Björk
    2017-08-09T23:36:36+08:002017-08-09T23:36:36+08:00

    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.

    • 7
  3. KumarHarsh
    2017-08-09T21:27:07+08:002017-08-09T21:27:07+08:00

    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, tblQuotesnã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:

    QuoteStatusID
    ProducerLocationID
    ProducerContactGuid
    EffectiveDate
    LineGUID
    OriginalQuoteGUID
    

    Notei também o seguinte código:

    DATEDIFF(D, @EffDateFrom, tblQuotes.EffectiveDate) >= 0 AND 
    DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <= 0
    

    é NON Sargableou seja, não pode utilizar índices.

    Para fazer esse código SARgablealterá-lo para isso:

    tblQuotes.EffectiveDate >= @EffDateFrom 
    AND  tblQuotes.EffectiveDate <= @EffDateFrom
    

    Para responder à sua pergunta principal, "por que você está recebendo uma chave Look up":

    Você está recebendo KEY Look upporque 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 Indexou Include 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:

    create nonclustered index tblQuotes_QuoteStatusID 
    on tblQuotes(QuoteStatusID)
    include(DisplayStatus);
    

    **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 SCANtambé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.

    • 4

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve