Oracle Tuning – Exportando Estatísticas de Tabelas

Fala PessoAll,

Depois de muito tempo sem postar, estou eu aqui de novo para falar de mais um recurso usado no nosso Diaadia.

Desta vez o problema foi o seguinte:

Temos uma base de produção 9i que está em plena fase de migração para 11g, claro que para que esta migração aconteça, temos que ter a homologação de vários sistemas em 11g, que atualmente rodam na nossa base de produção 9i. Em uma das homologações deste sistema, o analista nos acionou informando que um processo que rodava na base 9i em 10 minutos, já estava a mais de 1 hora rodando na base 11g, sem sucesso.

Vamos as análises…

Passo 1: Identificar que comando estava causando nosso problema, para isso solicitei ao analista rodar a rotina dele habilitando um trace, para tentarmos identificar. Foi solicitado adicionar os seguintes comandos na execução:

begin
--Habilita geracao do trace.
execute immediate('alter session set tracefile_identifier=''TRACE_PROC_LENTA''');
sys.dbms_support.start_trace(true, true);
-- Call the procedure
PROCEDURE_DO_ANALISTA_LENTA;
--Finaliza geracao do trace.
sys.DBMS_SUPPORT.STOP_TRACE;
end;
/

Após concluído o processo, temos que procurar na nossa pasta UDUMP o trace que foi gerado com o identificador “_TRACE_PROC_LENTA”.

Analisando o trace…

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 791 0.02 1.25 0 3 0 0
Execute 72124 9.77 127.63 365 3759 75246 7469
Fetch 81349 109.26 2466.37 229643 14999926 0 75146
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 154264 119.05 2595.27 230008 15003688 75246 82615

Identificamos que o processo rodou em 2595.27 segundos, total!

E temos um comando único, que rodou em 2289.73 segundos. Ficou claro que este é o culpado não??


select COL1, COL2, COL3 from MINHA_TABELA

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 5430 1.11 3.54 0 0 0 0
Fetch 5430 106.61 2286.19 222786 14703253 0 3431
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 10861 107.72 2289.73 222786 14703253 0 3431

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 214 (OWNER) (recursive depth: 1)

Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID MINHA_TABELA (cr=7 pr=0 pw=0 time=68 us cost=5 size=33 card=1)
13 INDEX RANGE SCAN MINHA_TABELA_IDX2 (cr=4 pr=0 pw=0 time=40 us cost=4 size=0 card=1)(object id 32870)

Como podemos ver, este select está sendo executado utilizando um índice, o MINHA_TABELA_IDX2. Ótimo, agora vamos comparar este plano de execução, com o plano de execução que temos em produção. Eis o plano de produção:


Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID MINHA_TABELA (cr=7 pr=0 pw=0 time=68 us cost=5 size=33 card=1)
13 INDEX RANGE SCAN MINHA_TABELA_PK (cr=4 pr=0 pw=0 time=40 us cost=4 size=0 card=1)

Opa…. qual a diferença? Nesta base a minha query acessa os dados pela PK, e não pelo índice! Matamos a parada!!!

Como resolver?

A base onde a homologação estava sendo feita era uma base 11g criada com uma cópia antiga de produção, que não vinha sendo coletada estatística, que estava sendo constantemente alterada pelos testes e que não estava 100%. Para coletar estatísticas novamente desta tabela, seria mais complicado e demorado, pois a tabela tem 667.000.000 de linhas, claro, o teste tem que ser agora!!!!

Lembramos então que tinhamos uma cópia fresquinha da base de produção, que tinha sido recém migrada para 11g, ou seja, estava em 11g, mas tinha as estatísticas certinhas de produção, onde a query estava rápida.

A solução encontrada foi: Exportar as estatísticas desta tabela.

Então, vamos lá…

Passo 1: Criar uma tabela de estatísticas na base origem, para receber as estatísticas atuais da tabela:


SQL> exec SYS.DBMS_STATS.CREATE_STAT_TABLE(ownname => 'DBAGABOS', stattab => 'TLISTENER_STATS');
Procedimento PL/SQL concluÝdo com sucesso.
SQL>

Passo 2: Exportar as estatísticas atuais da tabela na base de origem, para a tabela de esatísticas que você criou:


SQL> exec DBMS_STATS.EXPORT_TABLE_STATS(ownname => 'DBAGABOS', tabname => 'TLISTENER', stattab => 'TLISTENER_STATS', cascade => true);
Procedimento PL/SQL concluÝdo com sucesso.
SQL>

Passo 3: Exportar esta tabela gerada…


C:UsersGersonJr>exp dbagabos@orcl tables=TLISTENER_STATS file=dump_stats.dmp
Export: Release 10.2.0.3.0 - Production on Seg Ago 1 19:23:58 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Senha:
Conectado a: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
ExportaþÒo executada no conjunto de caracteres de WE8MSWIN1252 e no conjunto de caracteres de AL16UTF16 NCHAR
Sobre exportar tabelas especificadas ... via Caminho Convencional ...
. . exportando tabela TLISTENER_STATS 113 linhas exportadas
ExportaþÒo encerrada com sucesso, sem advertÛncias.
C:UsersGersonJr>

Passo 4: Importar a tabela de estatísticas que você exportou, no banco de destino…


C:UsersGersonJr>imp dbagabos@orcl_destino tables=TLISTENER_STATS file=dump_stats.dmp
Import: Release 10.2.0.3.0 - Production on Seg Ago 1 19:24:58 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Senha:
Conectado a: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
Arquivo de exportaþÒo criado por EXPORT:V10.02.01 via caminho convencional
AdvertÛncia: os objetos foram exportados por DBAGABOS; nÒo por vocÛ
importaþÒo realizada nos conjuntos de caracteres WE8MSWIN1252 e NCHAR AL16UTF16
. importando objetos de DBAGABOS para DBAGABOS
. importando objetos de DBAGABOS para DBAGABOS
. . importando table "TLISTENER_STATS" 113 linhas importadas
ImportaþÒo encerrada com sucesso, sem advertÛncias.
C:UsersGersonJr>

Passo 5: Importar as estatísticas para a tabela, lendo da tabela de estatísticas que você importou.

exec DBMS_STATS.IMPORT_TABLE_STATS(ownname => 'DBAGABOS', tabname => ‘TLISTENER’, stattab => ‘TLISTENER_STATS’, cascade => true, no_invalidate => true);

E agora é só você testar seu plano de execução e verificar se na base nova a query está se comportando da mesma forma que na base antiga.

Algumas considerações:
1 – O problema ocorreu na base 11g, porém para criar o post refiz os comandos na base instalada no meu PC, que é 10.2.0.3, como podem ver nos comandos acima.

2 – Estes passos não querem dizer que há uma garantia 100% da sua query ficar igual a sua base de origem, lembre-se que em performance existem inúmeros outros pontos que são verificados para o banco montar um plano de execução.

3 – A idéia deste post é mostrar este recurso de export/import de estatísticas, que é simples e rápido de fazer, e pode ajudar-nos em vários casos.

Qualquer coisa, estou à disposição para dúvidas e/ou sugestões!

Grande abraço.

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com

3 ideias sobre “Oracle Tuning – Exportando Estatísticas de Tabelas

  1. Fernando

    Muito bom esse blog!
    Queria aproveitar a oportunidade de comentário aqui e pedir uma ajuda..
    Estou querendo fazer alguns cursos de Oracle e pesquisando encontrei vários cursos de Oracle da Impacta… Alguém conhece? sabe se é bom?
    Cursos Oracle
    Abraço…

    Responder
    1. oracle Autor do post

      Obrigado Fernando.
      Volte sempre ao site, e caso queira pode indicar temas para que abordemos aqui.

      Vamos ver se os demais leitores falam alguma coisa sobre os cursos da Impacta, eu não conheço a instituição.

      Abraços!!

      Atc.
      Gerson Júnior
      gerson.vasconcelos@gmail.com

      Responder
  2. Cleber Nunes

    Gerson!

    Parabens pelo blog sobre o post acima, tive problema tambem ao migrar da versão 9i para a 11g, em relação as estatisticas so que o problema encontrado foi que a CPU do servidor windows ficava em 100%….apos uma analise na documentação constatei que necessitava excluir as estatisticas e coleta-las novamente….

    Abraços
    Cleber

    Responder

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *