Como acompanhamento desta pergunta sobre o aumento do desempenho da consulta, gostaria de saber se existe uma maneira de usar meu índice 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 em cluster no campo [ID] (pk) e um índice não em cluster em [DateEntered], [DeviceID]. A primeira consulta usa o índice em cluster, a segunda consulta usa meu índice não em cluster. Minha pergunta é de duas partes:
- Por que, como as duas consultas possuem uma cláusula WHERE no campo [DateEntered], o servidor usa o índice de cluster no primeiro, mas não no segundo?
- Como posso fazer com que o índice não agrupado seja usado por padrão nesta consulta, mesmo sem o orderby? (Ou por que eu não iria querer esse comportamento?)
Respostas:
a primeira consulta faz uma varredura de tabela com base no limite que expliquei anteriormente: É possível aumentar o desempenho da consulta em uma tabela estreita com milhões de linhas?
(provavelmente sua consulta sem a
TOP 1000
cláusula retornará mais de 46k linhas. ou em algum lugar entre 35k e 46k. (a área cinza ;-))a segunda consulta, deve ser ordenada. Como o índice NC é ordenado na ordem que você deseja, é mais barato para o otimizador usá-lo e, em seguida, para as pesquisas de indicadores no índice clusterizado para obter as colunas ausentes comparadas com a realização de uma varredura de índice clusterizado e a necessidade de para pedir isso.
inverta a ordem das colunas na
ORDER BY
cláusula e você retornará a uma varredura de índice em cluster, pois o NC INDEX é inútil.editar esqueceu a resposta para sua segunda pergunta, por que você não quer isso
O uso de um índice sem cobertura não agrupado em cluster significa que um ID da linha é pesquisado no índice NC e, em seguida, as colunas ausentes precisam ser pesquisadas no índice agrupado (o índice agrupado contém todas as colunas de uma tabela). As E / S para pesquisar as colunas ausentes no índice clusterizado são E / S aleatórias.
A chave aqui é ALEATÓRIA. 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 em cluster. Ele pode usar os mapas de alocação para procurar intervalos de varredura e apenas começar a ler o índice em cluster em grandes partes. Isso é seqüencial e muito mais barato. (contanto que sua tabela não esteja fragmentada :-)) A desvantagem é que o índice cluster INTEIRO precisa ser lido. Isso é ruim para o seu buffer e potencialmente uma enorme quantidade de pedidos de veiculação. mas ainda, E / S sequenciais.
No seu caso, o otimizador decide algo entre 35k e 46k linhas, é mais barato para uma varredura completa de índice em cluster. Sim, está errado. E em muitos casos, com índices estreitos e sem cluster, sem
WHERE
cláusulas seletivas ou uma tabela grande, isso dá errado. (Sua mesa é pior, porque também é uma mesa muito estreita.)Agora, adicionar o
ORDER BY
torna mais caro verificar o índice clusterizado completo e depois solicitar os resultados. Em vez disso, o otimizador assume que é mais barato usar o índice NC já solicitado e, em seguida, paga a penalidade aleatória de IO pelas pesquisas de favoritos.Portanto, seu pedido é um tipo de solução "dica de consulta" perfeita. MAS, em um determinado momento, quando os resultados da sua consulta forem tão grandes, a penalidade para as entradas / saídas aleatórias da pesquisa de favoritos será tão grande que se tornará mais lenta. Presumo que o otimizador altere os planos novamente para a verificação de índice em cluster antes desse ponto, mas você nunca sabe ao certo.
No seu caso, desde que suas inserções sejam ordenadas por data inserida, conforme discutido no bate-papo e na pergunta anterior (consulte o link), é melhor criar o índice de cluster na coluna DataDefinida.
fonte
Expressar a consulta usando sintaxe diferente às vezes pode ajudar a comunicar seu desejo de usar um índice não em cluster para o otimizador. Você deve encontrar o formulário abaixo para fornecer o plano que deseja:
Compare esse plano com o produzido quando o índice não agrupado é forçado com uma dica:
Os planos são essencialmente os mesmos (uma pesquisa de chave nada mais é do que uma pesquisa no índice de cluster). Os dois formulários de plano executam apenas uma consulta no índice não agrupado em cluster e no máximo 1000 pesquisas no índice agrupado.
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 em cluster. O otimizador trabalha substituindo partes de um plano lógico por operações relacionais equivalentes. A parte superior não é um operador relacional; portanto, a reescrita impede a transformação em uma varredura de índice em cluster. Se o otimizador fosse capaz de reposicionar o operador Top, ainda assim preferiria a varredura ao invés da pesquisa +, devido à maneira como a estimativa de custos funciona.
Custeio de varreduras e buscas
Em um nível muito alto, o modelo de custo do otimizador para varreduras e buscas é bastante simples: estima que 320 buscas aleatórias custam o mesmo que ler 1350 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 uma série de suposições simplificadoras, sendo uma delas a suposição de que toda consulta é iniciada sem dados ou páginas de índice já no cache. A implicação é que toda 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 estão na memória quando o processador de consultas precisa 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. Os pedidos subsequentes de linhas na mesma página provavelmente não terão 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) significa que o otimizador tende a mudar para uma verificação mais cedo do que provavelmente deveria. A E / S aleatória é apenas 'muito mais cara' do que a E / S 'seqüencial' se uma operação física resultar - o acesso a 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 modo que o padrão seja essencialmente seqüencial. Acrescente a isso a característica de desempenho variável dos sistemas de E / S modernos (especialmente de estado sólido) e tudo começa a parecer muito instável.
Metas de linha
A presença de um operador Top em um plano modifica a abordagem de custo. O otimizador é inteligente o suficiente para saber que encontrar 1000 linhas usando uma varredura provavelmente não exigirá a varredura de todo o índice em cluster - ele pode parar assim que 1000 linhas forem encontradas. Ele define uma 'meta de linha' de 1000 linhas no operador Top e usa informações estatísticas para trabalhar a partir daí para estimar quantas linhas ele espera precisar da origem da linha (uma varredura nesse caso). Eu escrevi sobre os detalhes deste cálculo aqui .
As imagens nesta resposta foram criadas usando o SQL Sentry Plan Explorer .
fonte