Home - www.devmedia.com.br

Tuning - Plano de Execução - Parte 3

Olá!

Continuaremos nosso estudo sobre planos de execução de queries discutindo um pouco mais sobre o processo de BookMark Lookup, representado pelo símbolo

No artigo anterior aprendemos que o processo de busca da página de dados à partir do ponteiro do índice irá ocorrer quando as colunas que compõem o índice não forem suficientes para retornar o resultado do comando select . Em outras palavras, o select está requisitando as colunas A e B com filtro em C e a estrutura do índice não-cluster comporta somente a coluna A.

Como vimos no artigo anterior, a query abaixo – que utiliza o índice EmployeeId , criado sobre a coluna de mesmo nome – ilustra essa situação .


PS: Para geração do plano, selecione Query...Display Estimated Execution Plan na barra de ferramentas do Query Analyzer ou aperte em conjunto <CTRL>+L

Agora uma questão:

Como melhorar a performance dessa query ?

Você poderia responder: “Mas porque melhorar a performance de uma query que roda tão rápido ? “. Pois é. As tabelas possuem um sério “defeito” – elas costumam crescer rapidamente e os problemas de performance sismam em crescer com elas.

Pensando com bom senso, se a tabela possui um número reduzido de linhas ( e “reduzido” também é um conceito muito relativo) você dificilmente precisará otimizar acesso. O que precisamos entender é como identificar objetos no plano que podem causam perda de performance e o que exatamente podemos fazer para contornar esse tipo de problema.

Existem duas coisas que fazem com que o otimizador selecione um índice para resolver uma query:

  • Seletividade : quanto menor o número de linhas que precisam ser lidas, mais rápido a query será executada. Para que a query seja eficiente, precisa encontrar um atalho também eficiente para resgatar dados. Para que o atalho não se torne um caminho sinuoso, são necessários filtros seletivos. A query está requisitando todos pedidos para employeeId=9 . Se um índice está sendo utilizado, isso significa que a “filtragem” para employeeId=9 é eficiente.
  • Cobertura : um índice que comporta todas as colunas presentes no comando select e cláusula where tem grandes chances de ser utilizado, mesmo em processos de scan (varreduras sequenciais). Índices são criados sobre um conjunto reduzido de colunas, conseqüentemente um processo de scan num índice certamente será mais eficiente que um processo de scan em páginas de dados, que concentram todas as colunas da tabela.

Concluímos que quanto mais próximo um índice estiver desses dois princípios - seletividade e cobertura -, maiores serão suas chances de utilização. Vamos aplicar esses princípios na otimização da query.

O primeiro passo será substituir o asterisco pelas colunas que realmente serão utlizadas . Nesse caso, as colunas necessárias são CustomerId e OrderDate . Vamos substituir e analisar o comportamento do plano:

O plano permaneceu inalterado porque as colunas CustomerId e OrderDate não fazem parte do índice, sendo necessário resgatá-las da página de dados. Vamos criar outro índice, acrescentando as colunas CustomerId e OrderDate:

create index ix_EmployeeId on Orders (EmployeeId, CustomerId, OrderDate)

Compare agora o plano de execução com os anteriores : o processo de BookMark Lookup sumiu !

Muitas vezes um índice não é utilizado porque, além de possuir baixa seletividade, não fornece a cobertura necessária para as colunas presentes na query . Índices desse tipo, além de ineficientes, são um contra-pêso nos processos de modificação de dados porque irão requerer atualização adicional nos processos de insert, update e delete.

Vamos fazer outro teste “dropando” o índice criado anteriormente ...

drop index Orders.ix_employeeId

... e executando a query abaixo:

O plano de execução continua SEM o processo de BookMark Lookup, mesmo referenciando a coluna OrderId que NÃO faz parte da estrutura do índice EmployeeId. Ora, se a coluna OrderId não pertence ao índice, não seria necessário um acesso adicional à página de dados ? A resposta é Não. Quer saber porquê ? Então não perca a continuação dessa matéria.

Um forte abraço a todos!

Paulo Ribeiro

 

Paulo Ribeiro (psribeiro@hotmail.com) é Microsoft MCDBA e membro da equipe editorial da SQL Magazine. Atua como DBA sênior em SQL Server na Livraria e Papelaria Saraiva S/A.

  Monitorando deadlocks com Trace Flags    
  Monitorando deadlocks com o Profiler    
  Variáveis tipo TABLE    
  Tabelas Temporárias    
  Subqueries Parte II: Queries correlatas    
  Subqueries – Parte I    
  Gerenciando Bloqueios–Parte II    
  Gerenciando Bloqueios–Parte I    
  Porque qualificar o owner na chamada de stored-procedures    
  Explorando os Tipos de Join – Parte II    
  Explorando os Tipos de Join – Parte I    
  Versões existentes do SQL Server 2000    
  Tuning - Plano de Execução no SQL Server - Parte 4    
  Tuning - Plano de Execução no SQL Server - Parte 3    
  Tuning - Plano de Execução no SQL Server - Parte 2    
  Tuning - Plano de Execução no SQL Server - Parte 1    
  Tuning - Estatísticas de I/O    
  Desfragmentando Índices no SQL Server    
  Procedures Não Documentadas
no SQL Server 2000 Parte 2
   
  Procedures Não Documentadas
no SQL Server 2000.
   
  SQL Server 2005 - YUKON    
  SQL Server 2000: o Contra-Ataque.    
  Boas-Vindas    
     

 

Todos os direitos reservados: DevMedia Group
SQL Magazine - 2004