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