Create Index não é Tuning!

Create Index não é Tuning!

Tempo de leitura: 3 minutos

Boa noite, galera, tudo bem?

Muita saudades de postar, mas, a correria esta demais. Prometo que vai ser mais frequente daqui pra frente. Gostaria de dedicar esse post para a equipe do Oracle (Carlos Carvalho, Anderson Ferreira, Alessandro Andrieta e Ricardo Argona) que trabalha comigo, estou aprendendo muito com eles, por exemplo, que produto Não utilizar…rs, brincadeira.

Hoje gostaria de falar sobre um assunto que é muito comum no mercado de trabalho. O DBA cria um índice  elimina um Key Lookup e se diz “especialista” em performance. Não quero julgar ninguém, mas, performance e tuning vai muito mais além do que isso, e eu gostaria de demonstrar isso nesse post.

Tenho uma procedure que tem uma instrução UPDATE que faz parte de 56,7% de custo do total da execução da procedure:

update A 

SET A.SPRD_LIQ_ACUM_M_ATU  = B.RES_SPREAD_LIQUIDACAO,     

A.RES_REF_LIQ_ACUM_M_ATU = B.RES_GAP_LIQUIDACAO    

FROM      #TB_DATA_BASE A     

INNER JOIN  

( SELECT ESTOQUE.ID_OPERACAO_DRCG,   ESTOQUE.NO_PARCELA,   ESTOQUE.IC_PAG_REC, 

RES_SPREAD_LIQUIDACAO = SUM(ESTOQUE.VL_RES_SPREAD_LIQUIDACAO),  

RES_GAP_LIQUIDACAO  = SUM(ESTOQUE.VL_RES_GAP_LIQUIDACAO) 

FROM  ESTOQUE_RES_RF ESTOQUE WITH(NOLOCK) 

INNER JOIN #TB_DATA_BASE A    ON ESTOQUE.ID_OPERACAO_DRCG = A.ID_OPERACAO_DRCG 

WHERE ESTOQUE.DT_ESTOQUE <= @PDT_BASE AND A.NO_PARCELA = ESTOQUE.NO_PARCELA     

AND A.IC_PAG_REC = ESTOQUE.IC_PAG_REC     

GROUP BY  ESTOQUE.ID_OPERACAO_DRCG,   ESTOQUE.NO_PARCELA,   ESTOQUE.IC_PAG_REC) AS B   

ON A.ID_OPERACAO_DRCG = B.ID_OPERACAO_DRCG     

AND A.NO_PARCELA = B.NO_PARCELA     

AND A.IC_PAG_REC = B.IC_PAG_REC

Analisando o plano de execução , podemos notar que a query que mais consomem mais recurso do plano. Vamos primeiro avaliar o maior vilão que no case é o update demonstrado anteriormente. Como pode ser visto no print, o SQL Server está realizando um Clustered Index Seek na tabela estoque_res_rf e essa operação está fazendo uma leitura de 711.152.000 registros. Porém, no final do processo, podemos perceber que o SQL Server apenas precisa de 48.558 registros. Esses registros são frutos do Join com a tabela temporária #TB_DATA_BASE. Thiago, que dizer que estou lendo mais registros do que preciso? A resposta é: SIM.

PlanoAtualSentry

Analisando o histograma de estatística do SQL Server, podemos ver que a estatística está Atualizada, mesmo que não seja FULLSCAN. Então provavelmente o problema não foi causado por estatísticas desatualizadas. O SQL Server está fazendo exatamente o que deveria ser feito. Vamos ver? Executo o comando que mostra as estatísticas do Índice pk_estoque_res_rf da Tabela ESTOQUE_RES_RF, que foi requisitada no print anterior.

 DBCC SHOW_STATISTICS (ESTOQUE_RES_RF,pk_estoque_res_rf)

O histograma abaixo, mostra a atualização das estatísticas e qual o seu último step no histograma do SQL Server que tem o RANGE_HI_KEY 2013-05-13 00:00:00.000, que é exatamente a Data Base utilizada como filtro para os comandos de UPDATE (descrito no inicio deste documento).

Estatistica

O filtro da query está utilizando um operador de “<=  @dataBase”, e  O SQL Serve tem que estimar TUDO menor que isso,nessa ocasião ele realiza a soma das colunas RANGE_ROWS e EQ_ROWS para chegar nesse valor. Por exemplo: 1403920 + 750,6796 + 1413610 até o primeiro step do histograma, assim , podendo abranger todos os valores.

Realizando o cálculo no excel  a soma foi algo em torno de 712.633.500 registros (O Valor não é o mesmo que o do plano acima, pois, ele foi estimado ontem e os dados já não são mais os mesmos do momento do plano). Nesse caso, apenas criar um indice não resolveria, pois, o SQL Server continuaria lendo todas as informações menor que a data especificada no parametro e, provavelmente o SLQ Sever optaria para ler o indice que contem mais páginas de dados, no caso o Clustered.

Nesse caso a sugestão seria Avaliar a alteração da query para adicionar filtros mais seletivos, evitando assim, a leitura total do Indice. O que poderia ser feito é adicionar um filtro para trazer valor “>= “ a partir de uma data “X”.  Realizando um teste para a data ‘2013-04-01 00:00.00.000’ e tive o seguinte resultado:

Evidencia

A pergunta é: no primeiro print o SQL Server fez um Clustered Index Seek para ler toda as informações da tabela, não seria mais fácil apenas realizar um Clustered Index Scan? Ess será assunto para o próximo post. Eu irei mostrar porque o SQL Server escolheu o Seek ao invés do Scan, uma coisa é fato: Para esse caso o Seek é mais eficiente, a pergunta é porque?

7 comentários

  1. Tu é muito fera meu amigo!

  2. Anderson Ferreira disse:

    Valeu Thi por ter lembrado da melhor equipe de Oracle do Itau!
    Ah cara parabens belo post e vc eh um pita profissional qualificado! E sabe o que faz!

  3. brizola disse:

    Tiago,
    seria legal você postar as duas querys para que todos pudessem ver como ficou. Eu entendi perfeitamente o que você quis dizer e realmente é isso mesmo. Só criar o índice, digitar sp_recompile e eliminar o lookup já ajuda, mas não é tudo . rs

    Eliminar funções sobre colunas no where e modelar a tabela correta são exemplos de técnicas de tuning que podem ser utilizadas.

    No mais, parabéns pelo artigo. Muito legal !

  4. Tiago Gomes disse:

    Bom dia Thiago.
    gostei muito do blog, em especifico a parte de Tuning. Estou fazendo minha monografia e gostaria muito de uma ajuda, gostaria de um contato seu para pedir uma ajuda, caso você possa dar. pode ser email, skype ou qualquer outra ferramenta de contato.
    muito grato e aguardo retorno. a proposito adicionei no linkedin.
    Tiago Gomes.

Deixe uma resposta

%d blogueiros gostam disto: