Freigeben über


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

  • 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, Tks

  • Anonymous
    March 27, 2008
    Ops, esqueci o Link, http://fabianosqlserver.spaces.live.com/blog/cns!52EFF7477E74CAA6!230.entry :-)