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


luciano.moreira@microsoft.com


 


=============================================================


This posting is provided “AS IS” with no warranties, and confers no rights


=============================================================

20080215 – Porque o SQL Server nao usa meu índice.zip

Comments (8)

  1. Chilá says:

    Problema de collation? o campo está como ID_Cliente e no script aparece como id_cliente…

    é um chute…

  2. 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.

  3. None says:

    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…

  4. Jonas says:

    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.

  5. Luciano, escrevi um pouco sobre isso no meu Blog, Tks

  6. Damasceno says:

    Cara, me desculpe… mas que post ridículo!

    Estou com esse problema/dúvida e procurando pelo Google cai nessa pagina onde simplesmente se escreve "É claro que eu NÃO vou responder o motivo do comportamento do SQL Server neste post".

    Então para que fez??? Para fazer hora com a cara dos outros???

    Pode querer falar que é para estimular a busca de conhecimento, p/ não receber nada de mão beijada…. Mas é justamente isso que fazemos quando lemos posts/artigos e outros na net. Procurar respostas e conhecimento é justamente o que estou fazendo.

    Esse comportamento é válido dentro de uma sala de aula, mas não aqui. Quando fazemos isso com nossos alunos eles vão a internet atras de conhecimento, e nesse caso se deparam com essa palhaçada de post.

    Nem link para outros estudos, nada tem nesse post.

    Me desculpe o desabafo, mas perdi um tempo valioso lendo o post (achando que tinha encontrado informação/conhecimento)(e perdi mais ainda escrevendo isso tudo [mas não resisti]) para no final NADA.

Skip to main content