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 / 23509
Accepted
Nate
Nate
Asked: 2012-09-01 06:49:11 +0800 CST2012-09-01 06:49:11 +0800 CST 2012-09-01 06:49:11 +0800 CST

Por que essa consulta não está usando meu índice não clusterizado e como posso fazer isso?

  • 772

Como acompanhamento desta pergunta sobre como aumentar o desempenho da consulta, gostaria de saber se existe uma maneira de tornar meu índice usado por padrão.

Esta consulta é executada em cerca de 2,5 segundos:

SELECT TOP 1000 * FROM [CIA_WIZ].[dbo].[Heartbeats]
WHERE [DateEntered] BETWEEN '2011-08-30' and '2011-08-31';

Este é executado em cerca de 33ms:

SELECT TOP 1000 * FROM [CIA_WIZ].[dbo].[Heartbeats]
WHERE [DateEntered] BETWEEN '2011-08-30' and '2011-08-31' 
ORDER BY [DateEntered], [DeviceID];

Há um índice clusterizado no campo [ID] (pk) e há um índice não clusterizado em [DateEntered],[DeviceID]. A primeira consulta usa o índice clusterizado, a segunda consulta usa meu índice não clusterizado. Minha pergunta é em duas partes:

  • Por que, uma vez que ambas as consultas têm uma cláusula WHERE no campo [DateEntered], o servidor usa o índice clusterizado na primeira, mas não na segunda?
  • Como posso fazer com que o índice não clusterizado seja usado por padrão nesta consulta mesmo sem o orderby? (Ou por que eu não iria querer esse comportamento?)
sql-server sql-server-2008-r2
  • 2 2 respostas
  • 33206 Views

2 respostas

  • Voted
  1. Paul White
    2012-09-06T05:43:20+08:002012-09-06T05:43:20+08:00

    Expressar a consulta usando uma sintaxe diferente às vezes pode ajudar a comunicar seu desejo de usar um índice não clusterizado para o otimizador. Você deve encontrar o formulário abaixo que lhe dá o plano que você deseja:

    SELECT
        [ID],
        [DeviceID],
        [IsPUp],
        [IsWebUp],
        [IsPingUp],
        [DateEntered]
    FROM [dbo].[Heartbeats]
    WHERE
        [ID] IN
    (
        -- Keys
        SELECT TOP (1000)
            [ID]
        FROM [dbo].[Heartbeats]
        WHERE 
            [DateEntered] >= CONVERT(datetime, '2011-08-30', 121)
            AND [DateEntered]  < CONVERT(datetime, '2011-08-31', 121)
    );
    

    Plano de consulta

    Compare esse plano com o produzido quando o índice não clusterizado é forçado com uma dica:

    SELECT TOP (1000) 
        * 
    FROM [dbo].[Heartbeats] WITH (INDEX(CommonQueryIndex))
    WHERE 
        [DateEntered] BETWEEN '2011-08-30' and '2011-08-31';
    

    Plano de dica de índice forçado

    Os planos são essencialmente os mesmos (uma Key Lookup nada mais é do que uma busca no índice clusterizado). Ambos os formulários de plano realizarão apenas uma busca no índice não clusterizado e um máximo de 1.000 pesquisas no índice clusterizado.

    A diferença importante está na posição do operador Top. Posicionado entre as duas buscas, o Top impede que o otimizador substitua as duas operações de busca por uma varredura logicamente equivalente do índice clusterizado. O otimizador funciona substituindo partes de um plano lógico por operações relacionais equivalentes. Top não é um operador relacional, portanto, a regravação impede a transformação em uma varredura de índice clusterizado. Se o otimizador pudesse reposicionar o operador Top, ele ainda preferiria a varredura em vez da busca + pesquisa devido ao modo como a estimativa de custo funciona.

    Custeio de scans e buscas

    Em um nível muito alto, o modelo de custo do otimizador para varreduras e buscas é bastante simples: ele estima que 320 buscas aleatórias custam o mesmo que ler 1.350 páginas em uma varredura. Isso provavelmente tem pouca semelhança com os recursos de hardware de qualquer sistema de E/S moderno em particular, mas funciona razoavelmente bem como um modelo prático.

    O modelo também faz várias suposições simplificadoras, sendo a principal delas que cada consulta deve começar sem dados ou páginas de índice já em cache. A implicação é que cada E/S resultará em uma E/S física - embora isso raramente seja o caso na prática. Mesmo com um cache frio, a pré-busca e a leitura antecipada significam que as páginas necessárias provavelmente estarão na memória no momento em que o processador de consulta precisar delas.

    Outra consideração é que a primeira solicitação de uma linha que não está na memória fará com que a página inteira seja buscada no disco. As solicitações subsequentes de linhas na mesma página provavelmente não incorrerão em uma E/S física. O modelo de custeio contém lógica para levar em conta efeitos como esse, mas não é perfeito.

    Todas essas coisas (e mais) significam que o otimizador tende a mudar para uma varredura mais cedo do que provavelmente deveria. A E/S aleatória é apenas 'muito mais cara' do que a E/S 'sequencial' se resultar de uma operação física - acessar páginas na memória é realmente muito rápido. Mesmo quando uma leitura física é necessária, uma varredura pode não resultar em leituras sequenciais devido à fragmentação, e as buscas podem ser colocadas de forma que o padrão seja essencialmente sequencial. Acrescente a isso a característica de desempenho variável dos sistemas de E/S modernos (especialmente de estado sólido) e a coisa toda começa a parecer muito instável.

    Metas de linha

    A presença de um operador Top em um plano modifica a abordagem de custeio. O otimizador é inteligente o suficiente para saber que encontrar 1.000 linhas usando uma varredura provavelmente não exigirá a varredura de todo o índice clusterizado - ele pode parar assim que 1.000 linhas forem encontradas. Ele define um 'objetivo de linha' de 1.000 linhas no operador Top e usa informações estatísticas para voltar a partir daí para estimar quantas linhas ele espera precisar da fonte de linha (uma varredura neste caso). Eu escrevi sobre os detalhes deste cálculo aqui .

    As imagens nesta resposta foram criadas usando o SQL Sentry Plan Explorer .

    • 21
  2. Best Answer
    Edward Dortland
    2012-09-01T06:55:44+08:002012-09-01T06:55:44+08:00

    a primeira consulta faz uma varredura de tabela com base no limite que expliquei anteriormente em: É possível aumentar o desempenho da consulta em uma tabela estreita com milhões de linhas?

    (provavelmente sua consulta sem a TOP 1000cláusula retornará mais de 46k linhas. ou algumas entre 35k e 46k. (a área cinza ;-))

    a segunda consulta, deve ser solicitada. Como seu índice NC é ordenado na ordem desejada, é mais barato para o otimizador usar esse índice e, em seguida, fazer as pesquisas de favoritos para o índice clusterizado para obter as colunas ausentes em comparação com uma verificação de índice clusterizado e, em seguida, precisar para ordenar isso.

    inverta a ordem das colunas na ORDER BYcláusula e você volta para uma varredura de índice clusterizado, pois o NC INDEX é inútil.

    edit esqueci a resposta para sua segunda pergunta, por que você NÃO quer isso

    Usar um índice não clusterizado não abrangente significa que um rowID é pesquisado no índice NC e, em seguida, as colunas ausentes devem ser pesquisadas no índice clusterizado (o índice clusterizado contém todas as colunas de uma tabela). As E/S para pesquisar as colunas ausentes no índice clusterizado são E/S aleatórios.

    A chave aqui é ALEATÓRIO. porque para cada linha encontrada no índice NC, os métodos de acesso precisam procurar uma nova página no índice clusterizado. Isso é aleatório e, portanto, muito caro.

    Agora, por outro lado, o otimizador também pode fazer uma varredura de índice clusterizado. Ele pode usar os mapas de alocação para pesquisar intervalos de varredura e apenas começar a ler o índice clusterizado em grandes partes. Isso é sequencial e muito mais barato. (desde que sua tabela não esteja fragmentada :-) ) A desvantagem é que o índice clusterizado INTEIRO precisa ser lido. Isso é ruim para o seu buffer e potencialmente uma grande quantidade de E/S. mas ainda assim, E/S sequenciais.

    No seu caso, o otimizador decide algo entre 35k e 46k linhas, é mais barato fazer uma varredura completa de índice clusterizado. Sim, está errado. E em muitos casos com índices não agrupados estreitos com WHEREcláusulas não seletivas ou tabelas grandes, isso dá errado. (Sua mesa é pior, porque também é uma mesa muito estreita.)

    Agora, adicionar o ORDER BYtorna mais caro verificar o índice clusterizado completo e, em seguida, ordenar os resultados. Em vez disso, o otimizador assume que é mais barato usar o índice NC já ordenado e, em seguida, pagar a penalidade de E/S aleatória para as pesquisas de favoritos.

    Portanto, seu pedido é um tipo de solução perfeita de "dica de consulta". MAS, em um certo ponto, uma vez que os resultados da sua consulta são tão grandes, a penalidade para os IOs aleatórios de pesquisa de favoritos será tão grande que se tornará mais lenta. Suponho que o otimizador mudará os planos de volta para a verificação de índice clusterizado antes desse ponto, mas você nunca sabe com certeza.

    No seu caso, desde que suas inserções sejam ordenadas por data de entrada, conforme discutido no chat e na pergunta anterior (veja o link), é melhor criar o índice clusterizado na coluna de data de entrada.

    • 10

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

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 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

    Como selecionar a primeira linha de cada grupo?

    • 6 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +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