Porque o SQL Server não usa o meu índice?
Atire a primeira pedra, ou mande o primeiro e-mail, quem nunca criou um índice para acelerar uma consulta e o SQL Server parece solenemente ignorar o bendito? Na seqüência o DBA ou desenvolvedor, depois de tentar algumas mudanças na consulta e analisar os planos de execução, chega (prematuramente?) à seguinte conclusão: a engine relacional do SQL Server para geração de planos de execução não é muito boa, pois não utilizou meu índice.
Minha visão sobre o comentário acima: sempre é interessante analisar o comportamento da engine para entender como o SQL Server funciona, mas é melhor ir com calma ao presumir (e criticar) sobre o comportamento da engine do SQL Server, pois por mais que você conheça o SQL Server, diversas vezes a engine utiliza otimizações inesperadas. No meu caso, mesmo já conhecendo um pouco sobre o produto, é freqüente eu ver alguma coisa que o SQL Server está fazendo e é muito mais inteligente do que eu esperava.
Também vale ressaltar que a cada nova versão do produto, Service Pack ou fix, a engine está sendo constantemente melhorada, para incluir alternativas não antes projetadas. É claro que a perfeição nunca será atingida e sempre existirão cenários de workloads que podem gerar planos ruins, e talvez até seja um bug. Porém, em linhas gerais você deve confiar na engine, sempre entendendo a motivação do SQL Server ao fazer uma escolha.
Chega de conversinha e vamos ao que interessa...
Pergunta: Porque o SQL Server não utiliza o índice não cluster que criei e é exatamente o critério da minha consulta?
A pergunta acima resume a questão levantada por um profissional que me enviou um e-mail recentemente. Reescrevo (com pequenas alterações) aqui o me foi exposto.
*****
Tenho uma dúvida. Utilizando o script em anexo você pode criar o banco para entender o cenário, que se trata de duas tabelas simples, cliente e pedido. A tabela de pedido referencia a tabela de cliente, para indicar quem fez a compra.
Para acelerar minha consulta, criei um índice não cluster na tabela pedido sobre o campo ID_Cliente, assim quando eu quiser filtrar os pedidos de um cliente específico o SQL Server utilizará este índice. Aqui está um exemplo da consulta que eu quero melhorar o desempenho:
Select vl_pedido from Pedido where id_cliente = 8
Porém, ao executar o comando acima, ele não utiliza o índice e faz um index scan na chave primária da tabela, que é um índice cluster. Gostaria de saber por que.
Inicialmente pensei que, pelo fato de ter poucos registros, ele achasse melhor utilizar um índice cluster, varrendo o índice a procura de pedidos de acordo com a cláusula “cliente = 8”. Mas depois fiz uma rotina, colocando os inserts em loop, para inserir 10 mil registros e ele continua fazendo index scan na PK, sendo que existe um índice não cluster no campo ID_Cliente. Gostaria de saber por que ele não utiliza o índice.
*****
Quem sabe o motivo disso acontecer? O SQL Server está fazendo alguma coisa errada? O índice nunca será usado? É um problema com as estatísticas?
É claro que eu NÃO vou responder o motivo do comportamento do SQL Server neste post, assim eu dou tempo para todos brincarem com o SQL Server.
PS1: A pessoa que enviou a pergunta não fez o comentário deste artigo, a minha observação é apenas uma dica de comportamento (será que posso fazer isso?) para aqueles que preferem criticar antes de entender o que está acontecendo.
PS2: não alterei o script para deixá-lo lindo, então arregacem as mangas e façam as alterações para fazê-lo funcionar.
PS3: quem assistiu a minha palestra no TechEd 2007, já deve saber a resposta.
[]s
Luciano Caixeta Moreira
=============================================================
This posting is provided "AS IS" with no warranties, and confers no rights
=============================================================
20080215 - Porque o SQL Server nao usa meu índice.zip
Comments
Anonymous
February 15, 2008
PingBack from http://www.biosensorab.org/2008/02/15/porque-o-sql-server-nao-usa-o-meu-indice/Anonymous
February 16, 2008
Problema de collation? o campo está como ID_Cliente e no script aparece como id_cliente... é um chute...Anonymous
February 17, 2008
Seletividade do indice, como a coluna vl_pedido não faz parte do indice noncluster o sql tera que fazer um bookmark para ler o valor de vl_pedido no indice cluster, um indice noncluster tem que retornar aproximadamente menos de 0.1% para fazer valer a pena o bookmark.Anonymous
February 18, 2008
Collation???? Ignorance is a bliss... Primeiro que case sensitiveness não tem nada a ver com collation... Segundo que as únicas coisas estúpidas que são case sensitive são linguagens baseadas em C e *nix...Anonymous
March 03, 2008
Inclui campo Vl_Pedido no índice e o Sql utilizou o index seek em ix_Pedido_ID_Cliente: CREATE NONCLUSTERED INDEX [ix_Pedido_ID_Cliente] ON [dbo].[Pedido] ( [ID_Cliente] ASC ) INCLUDE ( [VL_Pedido]) ON [PRIMARY] Não tenho a ciência do porquê, mas empiricamente acho que é mais custoso fazer um bookmark que um clustered index scan.Anonymous
March 27, 2008
Luciano, escrevi um pouco sobre isso no meu Blog, TksAnonymous
March 27, 2008
Ops, esqueci o Link, http://fabianosqlserver.spaces.live.com/blog/cns!52EFF7477E74CAA6!230.entry :-)