Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

22

Eu já sei a resposta para essa pergunta, mas sempre sinto que preciso entender mais sobre o assunto.

Meu entendimento básico é que, de um modo geral, um único índice que inclui apenas todos os campos nos quais você pode estar consultando / classificando a qualquer momento não é útil, mas já vi esse tipo de coisa. Alguém pensou: "Bem, se colocarmos tudo isso em um índice, o banco de dados pode usá-lo para encontrar o que precisa", sem nunca ter visto um plano de execução para algumas das consultas reais sendo executadas.

Imagine uma tabela como esta:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Talvez eu veja um único índice, incluindo os campos name, customerIde dateCreated.

Mas meu entendimento é que esse índice não seria usado em uma consulta como, por exemplo:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Para essa consulta, parece-me que uma idéia melhor seria um índice incluindo os campos customerIde dateCreated, com o customerIdcampo sendo o 'primeiro'. Isso criaria um índice que teria os dados organizados de forma que essa consulta pudesse encontrar rapidamente o que precisa - na ordem em que ela precisa.

Outra coisa que vejo, talvez tão freqüentemente quanto a primeira, são índices individuais em cada campo; por isso, cada um sobre name, customerIde dateCreatedcampos.

Diferentemente do primeiro exemplo, esse tipo de arranjo me parece às vezes pelo menos parcialmente útil; o plano de execução da consulta pode mostrar que pelo menos está usando o índice no customerIdpara selecionar os registros, mas não está usando o índice com o dateCreatedcampo para classificá-los.


Sei que essa é uma pergunta ampla, porque a resposta específica a qualquer consulta em particular em um determinado conjunto de tabelas é geralmente ver o que o plano de execução diz que vai fazer e, de outra forma, levar as especificidades da (s) tabela (s) e consultas para conta. Além disso, sei que depende da frequência com que uma consulta pode ser executada, em oposição à sobrecarga de manter um índice específico para ela.

Mas suponho que o que estou perguntando é como um "ponto de partida" geral para índices, a idéia de ter índices específicos para consultas específicas e freqüentemente puxadas e os campos nas cláusulas WHERE ou ORDER BY fazem sentido?

Andrew Barber
fonte

Respostas:

27

Você está certo em que sua consulta de exemplo não usaria esse índice.

O planejador de consultas considerará o uso de um índice se:

  • todos os campos contidos nele são referenciados na consulta
  • alguns dos campos que começam do início são referenciados

Não poderá usar índices que começam com um campo não usado pela consulta.

Então, para o seu exemplo:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

consideraria índices como:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

mas não:

[name], [customerId], [dateCreated]

Se encontrasse ambos [customerId]e [customerId], [dateCreated], [name]sua decisão de preferir um ao outro, dependeria das estatísticas do índice, que dependem das estimativas do balanço de dados nos campos. Se [customerId], [dateCreated]foram definidos, deve preferir isso aos outros dois, a menos que você dê uma dica específica ao contrário.

Também não é incomum ver um índice definido para cada campo em minha experiência, embora isso raramente seja ideal, pois o gerenciamento extra necessário para atualizar os índices na inserção / atualização e o espaço extra necessário para armazená-los são desperdiçados quando metade dos eles podem nunca ser usados ​​- mas, a menos que o seu banco de dados veja cargas pesadas de gravação, o desempenho não será ruim, mesmo com o excesso de índices.

Índices específicos para consultas frequentes que, de outra forma, seriam lentas devido à verificação de tabela ou índice geralmente são uma boa idéia, embora não exagere, pois você pode trocar um problema de desempenho por outro. Se você definir [customerId], [dateCreated]como um índice, por exemplo, lembre-se de que o planejador de consultas poderá usá-lo para consultas que usariam um índice apenas [customerId]se presente. Embora usar apenas [customerId]seja um pouco mais eficiente do que usar o índice composto, isso pode ser atenuado, acabando por haver dois índices competindo por espaço na RAM em vez de um (embora se todo o seu conjunto de trabalho normal se encaixe facilmente na RAM, essa competição extra de memória pode não ser um problema).

David Spillett
fonte
+1; ótimas informações, especialmente o lembrete (que costumo esquecer!) de que o planejador pode usar um índice composto em momentos em que precisa apenas do (s) primeiro (s) campo (s) dele para uma consulta.
Andrew Barber
6

Para responder à sua pergunta original, sim, os índices precisam ser projetados em torno das consultas , não apenas da tabela . A ordem dos campos no índice é de vital importância. Projetar um único índice para ser ideal para várias consultas é mais difícil, e você terá que fazer trocas.

Em relação ao seu segundo ponto, sim, um monte de índices em campos individuais únicos é irritantemente comum. Eu vejo isso o tempo todo no meu ambiente, e geralmente é uma bandeira vermelha para mim que a equipe de desenvolvimento não tenha trabalhado com um DBA para criar índices adequados.

Minha estratégia para projetar índices é indexar:

  • Campos usados ​​em WHERE (em ordem de seletividade)
  • Campos usados ​​em ORDER BY
  • Inclua outros campos (se necessário) para criar um índice de cobertura

Então, para o seu exemplo:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Eu provavelmente criaria um índice em (CustomerID, dateCreated) INCLUDE (id, nome). Esse índice de cobertura significa que a consulta nem precisa atingir a tabela original, melhorando bastante o desempenho.

Este exemplo é quase simples demais , no entanto. Um índice ingênuo em just (CustomerID) teria um desempenho quase bom (supondo que cada cliente tenha apenas um único representante, portanto, será necessária apenas uma pesquisa de marcador na tabela). Também pode ser benéfico realmente executar um índice em cluster (ID do cliente, ID), dependendo de outras consultas executadas na tabela.

BradC
fonte
O +1 para "os índices precisam ser projetados em torno das consultas, não apenas da tabela" e o restante da resposta, como por exemplo, observando que o exemplo é muito simples.
Andrew Barber