Por que a criação desse novo índice melhorou tanto o desempenho quando o índice existente incluiu todas as colunas no novo índice?

19

Eu tenho tabelas Log e LogItem; Estou escrevendo uma consulta para pegar alguns dados de ambos. Existem milhares Logse cada um Logpode ter até 125LogItems

A consulta em questão é complicada, por isso estou ignorando (se alguém acha importante, provavelmente posso publicá-la), mas quando executei o plano de Consulta Estimada do SSMS, ele me disse que um novo índice não clusterizado melhoraria o desempenho em até 100% .

Existing Index: Non-clustered
Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified

Query Plan Recommendation
CREATE NONCLUSTERED INDEX [LogReportIndex]
ON [dbo].[LogItem] ([ParentLogID],[DatabaseModified])

Apenas por diversão, criei esse novo índice e executei a consulta e, para minha surpresa, agora leva cerca de 1 segundo para que minha consulta seja executada, antes de mais de 10 segundos.

Eu supus que meu índice existente cobriria essa nova consulta; portanto, minha pergunta é por que a criação de um novo índice nas únicas colunas usadas na minha nova consulta melhorou o desempenho? Devo ter um índice para cada combinação exclusiva de colunas usada em minhas wherecláusulas?

nota: acho que isso não ocorre porque o SQL Server está armazenando meus resultados em cache, executei a consulta cerca de 25 a 30 vezes antes de criar o índice e demorou 10 a 15 segundos, depois que o índice agora está consistentemente ~ 1 ou menos.

Nate
fonte
Antes de você criar o índice não clusterizado adicional, o que o plano de execução real mostrou para o uso do índice?
Thomas Stringer
Qual é o desempenho aprimorado em 100%?
@ Shark Boa pergunta, não tenho certeza. Esta é minha primeira situação de depuração de desempenho. Eu vou ter certeza de pegar isso daqui para frente. Tudo o que dizia era "Índice ausente" e dizia quais campos.
@JeffO Foi o que o SSMS disse: "O Processador de consultas estima que a implementação do seguinte índice poderia melhorar o custo da consulta em 100%".

Respostas:

21

A ordem das colunas em um índice é importante. Se a filtragem exigir as colunas 1 e 4 do índice, o índice não ajudará. Só é útil ao filtrar pelas N primeiras colunas consecutivas.

Isso ocorre porque o índice é uma árvore. Você não pode selecionar com eficiência todos os nós da árvore onde column3 = something, porque eles estão espalhados por todo o outro lugar, pertencendo a diferentes valores de column1e column2. Mas se você souber column1e column2também, localizar o galho certo na árvore é um acéfalo.

GSerg
fonte
Seria seguro assumir (em geral) que eu preciso de um índice por conjunto de cláusulas "where" que atingirão essa tabela?
Certa vez, fiz uma aceleração maciça da consulta de outra pessoa apenas certificando-se de que ela usasse o índice na ordem correta.
1
@ Nate Em termos gerais, sim. Alguns wheres podem se sobrepor, então você pode ter um índice que cubra muito bem vários wheres; ou você pode ignorar parte de uma wherecláusula porque a indexação em uma determinada coluna não ajuda em nada (baixa seletividade); mas amplamente, sim.
@ Nate Você não quer ter mais índices do que o necessário. Cada índice que o SQL precisa manter adiciona uma sobrecarga própria. Se você pode reordenar suas cláusulas WHERE para corresponder às N primeiras colunas em um índice existente, isso deve levá-lo muito perto sem adicionar índices adicionais.
Esse Chuck Guy
1
@ChuckBlumreich A ordem das colunas nas wherecláusulas não é importante. O servidor sempre as organizará para fazer o melhor uso dos índices existentes. É apenas uma questão de ter um índice que inclua todas as wherecolunas necessárias como suas primeiras colunas.
12

A vantagem de um índice é o que importa.

Contanto que sua consulta seja "coberta" por uma borda principal de um índice, ela será eficiente. Os índices do banco de dados geralmente são implementados como Árvores B e a estrutura da Árvore B determina que a pesquisa deve ser feita em uma determinada ordem, e é por isso que a ordem dos campos no índice composto é importante.

Se você tiver "furos", por exemplo, se você pesquisar ParentLogIDe DatabaseModified, mas apenas tiver o índice ativado {ParentLogID, DateModified, Name, DatabaseModified}, somente a {ParentLogID}parte do índice poderá ser utilizada com eficiência.

(OBSERVAÇÃO: Alguns DBMSes podem utilizar a {DatabaseModified}parte através de "pular varredura", mas mesmo que o DBMS faça isso, é muito menos eficiente que o acesso regular ao índice) .

Branko Dimitrijevic
fonte
Então, se eu tenho Columns (a, b, c, d, e, f)e a maioria das consultas é o ... WHERE A IN(...) AND B = 3meu índice, Index(a,b,c,d)é bom, mas não ajuda se eu tiver, ... WHERE A IN (...) AND D = 5e é por isso que o meu novo índice que eu criei Index(a,d)melhorou muito o desempenho, certo?
8
@Nate - correto. Pense nisso como uma lista telefônica. Se você conhece apenas o primeiro nome de alguém, é impossível encontrá-lo sem examinar o livro inteiro, pois ele está organizado em Sobrenome, Nome
JNK