Pergunta

Se eu tiver uma consulta como:

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3)

e eu tenho um índice no EmployeeTypeId campo, o SQL Server ainda usa esse índice?

Foi útil?

Solução

Sim, está certo.Se sua tabela de funcionários tiver 10.000 registros e apenas 5 registros tiverem EmployeetypeID em (1,2,3), provavelmente usará o índice para buscar os registros.No entanto, se descobrir que 9.000 registros têm o EmployeeIDType em (1,2,3), então provavelmente faria apenas uma varredura de tabela para obter os EmployeeIDs correspondentes, pois é mais rápido percorrer toda a tabela do que ir para cada ramo da árvore de índice e observe os registros individualmente.

O SQL Server faz muitas coisas para tentar otimizar a forma como as consultas são executadas.No entanto, às vezes não obtém a resposta certa.Se você sabe que o SQL Server não está usando o índice, observando o plano de execução no analisador de consultas, você pode informar ao mecanismo de consulta para usar um índice específico com a seguinte alteração em sua consulta.

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId )) Where EmployeeTypeId IN (1,2,3)

Supondo que o índice que você possui no campo EmployeeTypeId seja denominado Index_EmployeeTypeId.

Outras dicas

Normalmente seria, a menos que a cláusula IN cubra muito da tabela, e então fará uma varredura na tabela.A melhor maneira de descobrir no seu caso específico seria executá-lo no analisador de consultas e verificar o plano de execução.

A menos que a tecnologia tenha melhorado de uma forma que não consigo imaginar ultimamente, a consulta "IN" mostrada produzirá um resultado que é efetivamente o OR de três conjuntos de resultados, um para cada um dos valores na lista "IN".A cláusula IN torna-se uma condição de igualdade para cada lista e usará um índice, se apropriado.No caso de IDs exclusivos e uma tabela grande o suficiente, esperaria que o otimizador usasse um índice.

No entanto, se os itens da lista não forem exclusivos, e eu acho que no exemplo um "TypeId" é uma chave estrangeira, então estou mais interessado na distribuição.Gostaria de saber se o otimizador verificará as estatísticas de cada valor da lista.Digamos que ele verifique o primeiro valor e descubra que está em 20% das linhas (de uma tabela grande o suficiente para ser importante).Provavelmente fará uma varredura na tabela.Mas será que o mesmo plano de consulta será usado para os outros dois, mesmo que sejam únicos?

Provavelmente é discutível - algo como uma tabela Employee provavelmente será pequeno o suficiente para permanecer armazenado em cache na memória e você provavelmente não notaria diferença entre isso e a recuperação indexada de qualquer maneira.

E por último, enquanto estou pregando, tome cuidado com a consulta na cláusula IN:geralmente é uma maneira rápida de fazer algo funcionar e (pelo menos para mim) pode ser uma boa maneira de expressar o requisito, mas quase sempre é melhor reformulado como uma junção.Seu otimizador pode ser inteligente o suficiente para detectar isso, mas talvez não.Se você atualmente não verifica o desempenho em relação aos volumes de dados de produção, faça-o - nestes dias de otimização baseada em custos, você não pode ter certeza do plano de consulta até ter uma carga completa e estatísticas representativas.Se não puder, então esteja preparado para surpresas na produção...

Portanto, existe o potencial de uma cláusula "in" para executar uma varredura de tabela, mas o otimizador tentará descobrir a melhor maneira de lidar com isso?

O uso de um índice não varia tanto no tipo de consulta, mas sim no tipo e na distribuição dos dados na(s) tabela(s), na atualização das estatísticas da tabela e no tipo de dados real da coluna .

Os outros postadores estão corretos ao dizer que um índice será usado em uma varredura de tabela se:

  • A consulta não acessará mais do que uma certa porcentagem das linhas indexadas (digamos aproximadamente 10%, mas deve variar entre os SGBDs).
  • Como alternativa, se houver muitas linhas, mas relativamente poucos valores exclusivos na coluna, também poderá ser mais rápido fazer uma varredura na tabela.

A outra variável que pode não ser tão óbvia é garantir que os tipos de dados dos valores comparados sejam os mesmos.No PostgreSQL, não acho que índices serão usados ​​se você estiver filtrando em um float, mas sua coluna for composta de inteiros.Existem também alguns operadores que não suportam o uso de índice (novamente, no PostgreSQL, o operador ILIKE é assim).

Porém, conforme observado, sempre verifique o analisador de consultas em caso de dúvida e a documentação do seu SGBD é sua amiga.

@Mike:Obrigado pela análise detalhada.Definitivamente, há alguns pontos interessantes que você destaca aí.O exemplo que postei é um tanto trivial, mas a base da questão veio do uso do NHibernate.

Com o NHibernate, você pode escrever uma cláusula como esta:

int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))

O NHibernate então gera uma consulta que se parece com

select * from employee where employeeid in (1, 5, 23463, 32523)

Então, como você e outros apontaram, parece que haverá momentos em que um índice será usado ou uma varredura de tabela acontecerá, mas você não pode realmente determinar isso até o tempo de execução.

Select EmployeeId From Employee USE(INDEX(EmployeeTypeId))

Esta consulta pesquisará usando o índice que você criou.Funciona para mim.Por favor, tente..

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top