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.
Respostas:
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 consultacol2
é 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=616
necessário, não é necessário um esforço extra para ler as páginas de dados: depois que as linhas de índice correspondentescol2=616
forem 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 aINCLUDE
clá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 exampletable
varrerá 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 4567
o mecanismo de consulta pode encontrar a primeira linha que corresponderá fazendo uma pesquisa baseada em árvore no índice e, emc1
seguida, poderá navegar no índice em ordem até chegar ao final do intervalo (o mesmo ocorre com uma consulta pois,c1=1234
como 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
TEXT
colunas ouVARCHAR(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
WHERE
ouJOIN ... ON
puder 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, oSELECT
agente solicita aoTOP
agente uma linha que, por sua vez, pede aoTABLE SCAN
agente para um, então oSELECT
agente pede para outro, mas oTOP
agente sabe que não há necessidade nem sequer pede ao leitor da mesa, oSELECT
agente 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.fonte
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/
fonte
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
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,
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.
fonte
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.
fonte