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 / 253192
Accepted
Click Ok
Click Ok
Asked: 2019-11-14 08:30:02 +0800 CST2019-11-14 08:30:02 +0800 CST 2019-11-14 08:30:02 +0800 CST

Por que esse índice de data e hora não está sendo usado?

  • 772

Tenho uma tabela assim:

CREATE TABLE TestTable
(
    [TestTableID] [int] IDENTITY(1,1) NOT NULL,
    [IntField1] [int] NOT NULL,
    [IntField2] [int] NOT NULL,
    [IntField3] [int] NOT NULL,
    [IntField4] [int] NOT NULL,
    [IntField5] [int] NOT NULL,
    [DateField1] [datetime] NOT NULL,
    [IntField6] [int] NOT NULL,
    [IntField7] [int] NOT NULL,
    [TextField1] [nvarchar](300) NULL,
    [DateField2] [datetime] NULL,
    [TextField2] [nvarchar](300) NULL,
    [DateField3] [datetime] NULL,
    [BoolField1] [bit] NULL
)

Eu criei um índice assim:

CREATE NONCLUSTERED INDEX IX_TestTable_DateField1
ON TestTable(DateField1);

E agora tenho esta consulta:

    DECLARE @startDate DATETIME = '20190101'
          , @endDate   DATETIME = '20200101'

    SELECT [TestTableID], 
           [IntField1], 
           [IntField2], 
           [IntField3], 
           [IntField4], 
           [IntField5], 
           [DateField1], 
           [IntField6], 
           [IntField7], 
           [TextField1], 
           [DateField2], 
           [TextField2],
           [DateField3], 
           [BoolField1]
      FROM TestTable
     WHERE DateField1 >= @startDate
       AND DateField1 < @endDate 

Essa tabela tem quase 10.000.000 de registros e essa consulta retornará cerca de 10.000 registros.

Agora, eu esperava que a consulta pelo menos usasse meu índice IX_TestTable_DateField1 ( Index Scan + Key Lookup ), mas está fazendo um Clustered Index Scan (no campo PK). Acho que é porque a consulta está retornando todos os campos da tabela.

Meu pensamento anterior era:

  1. Se o índice tiver INCLUÍDO todos os campos, então o SqlServer fará uma Busca de Índice;
  2. Se não incluir todos os campos, mas se o campo for usado em WHERE ou ORDER, usará Index Scan + Key Lookup;
  3. Se não for 1 ou 2, ele fará um Clustered Index Scan;

Isso está correto? Por que um "Index Scan + Key Lookup" não está acontecendo?

sql-server index
  • 3 3 respostas
  • 3901 Views

3 respostas

  • Voted
  1. Tibor Karaszi
    2019-11-14T09:24:07+08:002019-11-14T09:24:07+08:00

    O SQL Server pode definitivamente fazer uma busca de índice e depois uma pesquisa, mesmo quando você não cobre a consulta.

    O otimizador não tem ideia de quais valores você tem em suas variáveis ​​(é assim que as variáveis ​​funcionam). Então ele tem que adivinhar a seletividade. Você pode olhar para o plano de execução real e ver quantas linhas ele adivinha. Aparentemente, ele adivinha tantas linhas, então decide que é melhor fazer uma varredura de tabela (cl ix varredura).

    Se você adicionar OPTION(RECOMPILE) no final da consulta, deverá ver uma seletividade estimada diferente e potencialmente o uso do índice (tudo com base na seletividade que você tem no final).

    Além disso, se você tiver literais (os valores são conhecidos) ou parâmetros de procedimento armazenado (os valores são rastreados), verá como ele estimará de maneira diferente.

    • 4
  2. Best Answer
    Ronaldo
    2020-04-21T02:50:26+08:002020-04-21T02:50:26+08:00

    Aqui está o que a Microsoft diz sobre a otimização de instruções SELECT

    O SQL Server Query Optimizer é um otimizador baseado em custo. Cada plano de execução possível tem um custo associado em termos da quantidade de recursos computacionais utilizados. O Otimizador de Consultas deve analisar os planos possíveis e escolher aquele com o menor custo estimado.

    [...]

    O SQL Server Query Optimizer não escolhe apenas o plano de execução com o menor custo de recursos; ele escolhe o plano que retorna resultados ao usuário com um custo razoável em recursos e que retorna os resultados mais rapidamente. Por exemplo, processar uma consulta em paralelo normalmente usa mais recursos do que processá-la em série, mas conclui a consulta mais rapidamente.

    Como você pode ver, o Query Optimizer escolherá o plano que espera obter a execução mais eficiente. Às vezes, usar um (Index Scan + Key Lookup) não é o método mais eficiente.

    Como teste, você pode comparar os resultados do plano de execução STATISTICS TIME e STATISTICS IO que está obtendo agora com os gerados para sua consulta, forçando-a a usar o índice com uma dica de consulta . Por favor, note que não estou aconselhando você a usar esta dica como solução, mas como uma forma de comparar como seria o desempenho da execução se usasse o índice como você deseja.


    Para leitura adicional, o artigo de Benjamin Nevarez traz algumas boas informações: O SQL Server Query Optimizer

    • 2
  3. John K. N.
    2020-04-21T04:13:32+08:002020-04-21T04:13:32+08:00

    O problema que você está observando tem a ver com a maneira como o SQL Server determina a melhor maneira de executar uma consulta e é chamado de detecção de parâmetros.

    Leitura de referência

    • Sniffing de Parâmetros em Ação (Brent Ozar)
    • SQL SERVER – Exemplo mais simples de detecção de parâmetros (autoridade do SQL Server)

    O que?

    Quando você executou sua consulta pela primeira vez, o SQL Serer Query Optimizer com a ajuda do Cardinality Estimator usou as estatísticas dos índices disponíveis para determinar de que maneira recuperar os dados que você estava solicitando.

    Agora, se os valores que você passou para as variáveis ​​foram inicialmente como o seguinte:

    DECLARE @startDate DATETIME = '19010101'
          , @endDate   DATETIME = '20200101'
    

    ..então o Query Optimizer rapidamente determinou que precisaria varrer todos os dados no índice IX_TestTable_DateField1para recuperar todas as linhas (ou possivelmente até um pouco mais de 50% de todos os dados) para preencher a instrução com eficiência.

    Em vez de usar o IX_TestTable_DateField1índice para recuperar todos os registros para corresponder à sua consulta, o otimizador de consulta optou por ler o índice clusterizado porque o índice clusterizado está em vigor nos dados. (Por que ler um índice não clusterizado para recuperar os dados, quando você pode ler o índice clusterizado e já possui os dados).

    Como essa foi a primeira execução, o Query Optimizer armazenou o plano de execução (otimizado para os valores iniciais) no cache do plano.

    Sempre que uma nova consulta (com valores diferentes) chegar ao servidor, o QO verá que já possui um plano de execução que atende aos requisitos da consulta.

    O grande contratempo é que o plano de consulta foi otimizado para os valores iniciais e quando você fornece novos valores para os parâmetros, o QO não vai criar um novo plano de consulta, porque isso é "caro".

    Solução

    Se você quiser que sua consulta use o índice, você terá que:

    • executarWITH RECOMPILE
    • execute a consultaWITH OPTIMIZE FOR @startDate = '<value>', @endDate = '<value>'
    • execute a consultaWITH OPTIMIZE FOR UNKNOWN
    • remova o plano de consulta do cache do plano

    Depois disso, você pode observar que os dados são recuperados usando seu índice.

    Leitura de referência

    • Dicas de consulta (Tranact SQL) (Microsoft | SQL Docs)
    • 2

relate perguntas

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

  • Quanto "Padding" coloco em meus índices?

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

  • O que significa "índice" em RDBMSs? [fechado]

  • Como criar um índice condicional no MySQL?

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