Procura de índice x varredura de índice


64

Analisando um plano de execução de uma consulta de execução lenta, notei que alguns dos nós são busca de índice e alguns são verificação de índice.

Qual é a diferença entre e busca de índice e uma verificação de índice?

Qual funciona melhor?

Como o SQL escolhe um sobre o outro?

Sei que são três perguntas, mas acho que responder à primeira irá explicar as outras.


6
Você tem uma boa referência em use-the-index-luke .
Marian

7
Nem todas as verificações são ruins - às vezes é a maneira mais eficiente de satisfazer a consulta. Observe também que nem todas as buscas são buscas - geralmente são na verdade varreduras de intervalo, e a busca indica apenas como chegou ao início do intervalo.
Aaron Bertrand

@AaronBertrand, mas se chegar ao início do intervalo e lê-lo, significa basicamente que você precisa dos dados de qualquer maneira. Além disso, ele busca o fim do intervalo.
George Polevoy

Respostas:


76

Versão curta: procurar é muito melhor

Versão menos curta: geralmente, a busca é muito melhor, mas muitas buscas (causadas por um design de consulta incorreto com subconsultas correlatas desagradáveis, por exemplo, ou porque você está fazendo muitas consultas em uma operação do cursor ou em outro loop) podem ser piores que um varredura, especialmente se sua consulta acabar retornando dados da maioria das linhas na tabela afetada.

Ajuda a cobrir toda a família para operações de localização de dados para entender completamente as implicações de desempenho.

Verificações de tabela: sem nenhum índice relevante para sua consulta, o planejador é forçado a usar uma verificação de tabela, o que significa que todas as linhas são examinadas. Isso pode resultar em todas as páginas relacionadas aos dados da tabela sendo lidas do disco, o que geralmente é o pior caso. Observe que, em algumas consultas, ele usará uma varredura de tabela mesmo quando um índice útil estiver presente - isso geralmente ocorre porque os dados na tabela são tão pequenos que é mais difícil percorrer os índices (se esse for o caso, você esperaria que o planeje mudar conforme os dados aumentem, supondo que a medida de seletividade do índice seja boa).

Varreduras de índice com pesquisas de linha: sem nenhum índice que possa ser usado diretamente para uma procura, mas um índice contendo as colunas da direita estiver presente, uma varredura de índice pode ser usada. Por exemplo, se você tiver uma tabela grande com 20 colunas com um índice na coluna1, col2, col3 e emitir SELECT col4 FROM exampletable WHERE col2=616, nesse caso, a varredura do índice para consulta col2é melhor do que a varredura da tabela inteira. Depois que as linhas correspondentes são encontradas, as páginas de dados precisam ser lidas para capturar col4 para saída (ou associação adicional), que é o estágio "pesquisa de marcador" quando você a vê nos planos de consulta.

Varreduras de índice sem pesquisas de linha: se o exemplo acima foi SELECT col1, col2, col3 FROM exampletable WHERE col2=616necessário, não é necessário um esforço extra para ler as páginas de dados: depois que as linhas de índice correspondentes col2=616forem encontradas, todos os dados solicitados serão conhecidos. É por isso que às vezes você vê colunas que nunca serão pesquisadas, mas provavelmente serão solicitadas para saída, adicionadas ao final dos índices - ele pode salvar pesquisas de linhas. Ao adicionar colunas a um índice por esse motivo e apenas por esse motivo, adicione-as com a INCLUDEcláusula para informar ao mecanismo que ele não precisa otimizar o layout do índice para consultas com base nessas colunas (isso pode acelerar as atualizações feitas nessas colunas) . As varreduras de índice também podem resultar de consultas sem cláusulas de filtragem: SELECT col2 FROM exampletablevarrerá este exemplo de índice em vez das páginas da tabela.

Procura de índice (com ou sem pesquisas de linha) : em uma busca, nem todo o índice é considerado. Para a consulta, SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567o mecanismo de consulta pode encontrar a primeira linha que corresponderá fazendo uma pesquisa baseada em árvore no índice e, em c1seguida, poderá navegar no índice em ordem até chegar ao final do intervalo (o mesmo ocorre com uma consulta pois, c1=1234como pode haver muitas linhas correspondentes à condição, mesmo para uma =operação). Isso significa que apenas as páginas de índice relevantes (mais algumas necessárias para a pesquisa inicial) precisam ser lidas em vez de todas as páginas do índice (ou tabela).

Índices em cluster : com um índice em cluster, os dados da tabela são armazenados nos nós folha desse índice, em vez de estarem em uma estrutura de heap separada. Isso significa que nunca será necessário fazer pesquisas adicionais de linha após localizar linhas usando esse índice, independentemente das colunas necessárias [a menos que você tenha dados fora da página, como TEXTcolunas ou VARCHAR(MAX)colunas que contêm dados longos].

Você pode ter apenas um índice clusterizado por esse motivo [1] , o índice clusterizado é a sua tabela em vez de ter uma estrutura de heap separada; portanto, se você usar um [2], escolherá onde colocá-lo com cuidado para obter o máximo ganho.

Observe também que o índice em cluster porque a "chave de cluster" da tabela está incluída em todos os índices não em cluster da tabela; portanto, um índice em cluster amplo geralmente não é uma boa idéia.

[1] Na verdade, você pode efetivamente ter vários índices clusterizados definindo índices não clusterizados que cobrem ou incluem todas as colunas da tabela, mas é provável que seja um desperdício de espaço que tenha um impacto no desempenho de gravação, portanto, se você considerar fazer isso, verifique se você realmente precisa.

[2] Quando eu digo "se você usar um índice de cluster", note que é geralmente recomendado que você faça ter um em cada tabela. Há exceções, como em todas as regras práticas, as tabelas que veem pouco além de inserções em massa e leituras não ordenadas (tabelas de preparação para processos de ETL, talvez) sendo o exemplo de contador mais comum.

Ponto adicional: Varreduras incompletas:

É importante lembrar que, dependendo do restante da consulta, uma varredura de tabela / índice pode na verdade não varrer a tabela inteira - se a lógica permitir que o plano de consulta consiga fazer com que seja interrompido mais cedo. O exemplo mais simples disso é SELECT TOP(1) * FROM HugeTable: se você olhar para o plano de consulta, verá que apenas uma linha foi retornada da varredura e se observar as estatísticas de E / S ( SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable), verá que ele lê apenas um número muito pequeno. de páginas (talvez apenas uma).

O mesmo pode acontecer se o predicado de uma cláusula WHEREou JOIN ... ONpuder ser executado simultaneamente com a varredura que é a origem e seus dados. Às vezes, o planejador / corredor de consulta pode ser muito inteligente ao enviar predicados de volta às fontes de dados para permitir o encerramento antecipado das verificações dessa maneira (e às vezes você pode reorganizar as consultas para ajudá-lo!). Enquanto os dados fluem da direita para a esquerda, conforme as setas na exibição do plano de consulta padrão, a lógica é executada da esquerda para a direita e cada etapa (da direita para a esquerda) não é necessariamente executada até a conclusão antes que a próxima possa começar. No exemplo simples acima, se você olhar para cada bloco no plano de consulta como um agente, o SELECTagente solicita ao TOPagente uma linha que, por sua vez, pede aoTABLE SCANagente para um, então o SELECTagente pede para outro, mas o TOPagente sabe que não há necessidade nem sequer pede ao leitor da mesa, o SELECTagente recebe uma resposta "não é mais relevante" e sabe que todo o trabalho está feito. Muitas operações de bloquear este tipo de otimização é claro tantas vezes em exemplos mais complicados uma varredura na tabela / index realmente não ler cada linha, mas tome cuidado para não saltar para a conclusão de que qualquer verificação deve ser uma operação cara.


6

Geralmente, as buscas são boas, as varreduras são ruins.

As buscas são onde a consulta pode fazer uso efetivo do índice e usá-lo para encontrar as linhas necessárias.

As verificações são onde a consulta está examinando todo o índice, tentando encontrar o que precisa.

Como o SQL escolhe? Nos detalhes internos do otimizador de consulta, a decisão é tomada com base na sua consulta e nos índices disponíveis e nas informações estatísticas associadas a esses índices.

Existem alguns livros para ler que podem ser interessantes aqui - Ambos da livraria Red-Gate em http://www.red-gate.com/community/books/

  • Planos de execução do SQL Server por Grant Fritchey
  • Por dentro do otimizador de consultas de Benjamin Nevarez
  • Estatísticas do SQL Server por Holger Schmeling

7
Para o mesmo plano, uma varredura de tabela única é boa, um milhão de buscas é ruim. Portanto, sua primeira afirmação não está totalmente correta.
Marian

De fato, a busca de índice e a varredura de índice cada uma tem seu próprio uso; você não pode dizer que uma é melhor que outra SEM o contexto de tabelas e consultas subjacentes. Na maioria das vezes, se uma tabela tem suas estatísticas imprecisas, o plano de execução pode ficar abaixo do ideal, como uma busca de índice que é escolhida por engano sobre uma varredura de índice e vice-versa.
jyao

5

Se você deseja explorar o assunto, um livro muito útil (pelo menos para mim) é o SQL Server Execution Plans de Grant Fritchey, disponível gratuitamente no RedGate aqui .

Se você tiver uma consulta como

SELECT *
FROM myTable

O SQL Server provavelmente usará uma verificação de índice, pois precisa passar por todas as linhas para exibir os resultados necessários.

Pelo contrário,

SELECT *
FROM myTable
WHERE myID = 1

certamente resultará em uma busca no índice. O SQL Server usará a estrutura em árvore B do índice myID e a recuperação da linha correta será muito mais rápida.


Não sei se concordo com "certamente" - mesmo que um índice possua myID como uma coluna principal, uma busca pode não ser a resposta ideal (depende de muitas coisas, como se é única - que pode ser true na tabela customers, mas não para customerID na tabela orders, quantas colunas precisam ser cobertas, mas não estão no índice etc.).
Aaron Bertrand

Eu não acho que essa resposta realmente cubra as perguntas colocadas.
Zero3 23/02

5

Outros definiram bem o suficiente as diferenças entre procurar e verificar. Nesse caso, sua própria consulta e o planejador de execução devem fornecer as informações necessárias para ver quais valores são usados ​​como predicados (filtros) para a consulta em cada parte. Normalmente, é uma boa prática sempre adicionar índices não agrupados em chaves estrangeiras e, dependendo dos casos de uso no código do programa, convém criar índices adicionais de várias colunas ou incluir índices de colunas também. Com a terminologia apresentada aqui, uma pesquisa no Google fornecerá resultados decentes nos exemplos de cada um.

Mas, como exemplo, digamos que seu código está consultando as Colunas A e B nos filtros fornecidos, mas você também deseja retornar os valores das Colunas C e Coluna E, convém criar um índice nas Colunas A e B com o INCLUDE opção que contém as colunas C e E. Dessa maneira, uma única busca de índice retornará tudo o que você precisa, pois não é necessário fazer uma pesquisa para recuperar os outros valores (C e E) na mesma linha.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.