DBMS_STATS.RESTORE_TABLE_STATS – Pluft, Plact, Zuummm

Olá DBAs, a vida tá boa?

No meu último post sobre Oracle Pending Statistics, ainda perto da introdução, eu falei sobre uma proc salvadora, que pode te tirar do fogo no meio da sala de guerra, só pra dar aquela respirada, colocar o sistema de volta ao funcionamento e pode então pensar no que fazer. Falei da procedure DBMS_STATS.RESTORE_TABLE_STATS.

Alguns DBA´s me perguntaram sobre essa procedure, e devido a isso, decidi escrever aqui sobre ela. Pra voce que não conhece, será um prazer te apresentá-la. Pra voce que conhece, dá uma lida mesmo assim, vai que tem algo que voce ainda não se ligou.

Era Domingo, 2:00 da manhã, o telefone toca…
Nããããããããooooooo!!! Não vou fazer isso com voces! LOL. (Alguns amigos reviraram os olhos ao ler…huauhahuahua)

Vamos ao que interessa.

Voce provavelmente em algum ponto da sua carreira já viu esse cenário:

03:00 AM08:00 AM08:05 AM08:20 AM
Auto gather statistics roda.Usuário começa a reclamar.Query que rodava em segundos agora demora minutos.Voce tá na sala de guerra tentando descobrir o que aconteceu.

“ué… por que o optimizer resolveu fazer ISSO agora?”

– Joãozinho, DBA desesperado, 2026.

As vezes, a resposta é mais simples do que parece: As estatísticas mudaram!

É exatamente nesse tipo de situação que entra uma das procedures mais úteis do pacote DBMS_STATS, ela é uma espécie de “rollback de estatística”.

Afinal, o que essa procedure faz?

Ele restaura estatísticas antigas de uma tabela utilizando o histórico armazenado pelo Oracle.

Ou seja:

  • volta stats antigas
  • volta histogramas antigos
  • volta NDV/density antigos
  • pode ajudar a recuperar planos antigos

O que essa procedure NÃO faz?

  • NÃO restaura dados
  • NÃO desfaz DML
  • NÃO faz flashback da tabela

Ele trabalha exclusivamente na camada de optimizer, nada de dados ou estrutura.

Resumindo, o Oracle mantém histórico de stats. Quando você executa gathers usando DBMS_STATS, o Oracle normalmente salva versões anteriores automaticamente no dicionário. Essas informações ficam armazenadas na SYSAUX. Assim voce pode:

  • consultar histórico;
  • comparar versões;
  • restaurar stats antigas;
  • investigar regressões.

Exemplo básico de uso da procedure de restore

Se o meu ambiente ficou ruim após as 08 da manhã (horário em que os usuários começaram a trabalhar e já começaram a reclamar), e checando eu verifiquei que houve uma coleta as 05 da manhã, uso a seguinte sintaxe pra voltar:

BEGIN
   DBMS_STATS.RESTORE_TABLE_STATS(
      ownname => 'VALDZ',
      tabname => 'TEST_RESTORE_STATS',
      as_of_timestamp => TO_TIMESTAMP('2026-04-12 04:59:00','YYYY-MM-DD HH24:MI:SS')
   );
END;
/

Esse comando já vai te ajudar a voltar ao estado de stats anterior, e em teoria já vai resolver seu problema. É importante frizar que o Oracle não faz um “flashback exato” das stats, mas sim ele procura pela versão mais próxima disponível que seja anterior ao timestamp pedido.

É comum acontecerem problemas onde voce não tinha histogram sendo coletado (por decisão do próprio Oracle com “METHOD_OPT => ‘FOR ALL COLUMNS SIZE AUTO'”, e aí na última coleta ele decidiu coletar histogramas, fazendo aquela bagunça em join order, cardinalidade, uso de temp e etc…, neste casos, a proc vai te ajudar muito, pois te devolve os stats antigos sem os hitogramas bagunçando tudo. Aí com o ambiente de volta e funcionando em performance aceitável, voce pode analisar e decidir o que fazer, talvez testando coletas com histogramas usando um numero de buckets mais específicos, ou mesmo não deixando mais o Oracle decidir automaticamente, e aqui é um ótimo exemplo de como usar a procedure do post anterior (pending statistics).

E se o restore não resolver? Sim, pode acontecer! Voce precisa ter em mente que o restore não garante que o plano voltará a ser igual, mas sim que as estatísticas serão as mesmas de antes, e teoricamente o Oracle voltará a usar o mesmo plano, mas isso depende de muita coisa (bind peeking, adaptive plans, cardinality, optimizer, patches, etc…). Estatísticas iguais as anteriores não significam necessariamente plano igual ao anterior (mas por experiencia, resolve na maioria dos casos).

Obviamente nem preciso dizer né, que os cursores serão invalidados e as queries passarão por hard parse novamente, afinal, como ele criaria os novos planos? E é por isso que no parágrafo anterior falo sobre os planos poderem vir a ser diferentes mesmo com o restore das stats.

Posso restaura um schema inteiro? Posso.

Mas sinceramente, na maioria das vezes a análise nos leva para intervenções mais cirúrgicas. Inclusive é possível restaurar as stats para um única partição se preciso.

Para restaurar as stats de um schema inteiro: DBMS_STATS.RESTORE_SCHEMA_STATS

Para restaurar as stats de uma partição específica:
BEGIN
   DBMS_STATS.RESTORE_TABLE_STATS(
      ownname => 'VALDZ',
      tabname => 'TEST_RESTORE_STATS',
      partname => 'P2026_MAY',
      as_of_timestamp => SYSTIMESTAMP - 1
   );
END;
/

Seguem duas queriezinhas também para te ajudar a verificar se as estatísticas mudaram:

SELECT table_name, last_analyzed
FROM dba_tables
 WHERE owner = 'VALDZ'
AND table_name = 'TEST_RESTORE_STATS';

SELECT *
FROM dba_tab_stats_history
WHERE table_name = 'TEST_RESTORE_STATS'
ORDER BY stats_update_time DESC;

Lembre-se, quanto maior o tempo de retenção, mais espaço voce estará consumindo na SYSAUX.

A documentação fala de um padrão de retenção de 31 dias, em tempo, corridos, não em número de coletas. Muita gente lembra que o Oracle guardava ‘31 coletas’. Mas tecnicamente o histórico sempre foi baseado em dias, não em quantidade de gathers. O que acontecia é que, em muitos ambientes antigos, havia apenas uma coleta diária — então 31 dias acabavam parecendo 31 versões, ledo engano.

Então se voce tiver 1 coleta por semana, com a configuração de retenção padrão voce terá em teoria 4 versões possíveis de stats para restaurar (faz a continha aí no papel de pão). Mas essa configuração é modificável, pela procedure GET_STATS_HISTORY_RETENTION dentro do DBMS_STATS.

Eu considero o DBMS_STATS.RESTORE_TABLE_STATS uma das ferramentas mais importantes de troubleshooting no Oracle, principalmente em salas de guerra. Ele te permite fazer um rollback rápido das stats, estabilizar o ambiente, recuperar a regressão e ter tempo para RCA(root cause analysis) de maneira adequada e com uma menor pressão.

Apesar de ser o que chamamos de “mão na roda”, lembre-se, normalmente a regressão é apenas sintoma de algo maior que PRECISA sim ser verificado, como skew, histogram inadequado, cardinality errada, comportamento instável do optimizer e por aí vai.

Mas ainda assim, quando o ambiente estiver pegando fogo logo depois de uma coleta de estatísticas, esse cara vai ser seu grande amigo e aliado, pra te dar save ali naquele momento. Aí voce respira, arregaça as mangas, e corre pra descobrir o motivo.. hehehehe

Fiquem a vontade para fazer quaisquer pontuações caso já tenham usado, falaí, o que voce achou? Já te salvou?

Essa é a dica 0800 pra voces desta vez.

“Saber das coisas vale ouro. Compartilhar esse conhecimento não tem preço.”

Deixe um comentário

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