iceranto.dev / log

Diagnóstico de performance Oracle: o que olhar primeiro

Por onde começar

Quando o sistema fica lento e a culpa cai no banco, o instinto é sair executando queries aleatórias em V$SESSION. Isso raramente funciona. Existe uma ordem lógica.

1. Confirmar que o problema é no banco

Antes de qualquer coisa: o gargalo é no banco ou na aplicação?

Verifico o tempo de resposta ponta a ponta com APM ou logs da aplicação. Se a query demora 50ms no banco mas a request leva 3s, o problema está em outro lugar.

2. AWR: visão macro

O AWR (Automatic Workload Repository) é o ponto de partida para análise histórica.

-- Listar snapshots disponíveis
SELECT snap_id, begin_interval_time, end_interval_time
FROM dba_hist_snapshot
ORDER BY snap_id DESC
FETCH FIRST 20 ROWS ONLY;

Gero o relatório HTML entre dois snapshots do período problemático e foco em:

  • Top 5 Timed Events — onde o banco passou o tempo
  • Top SQL by Elapsed Time — SQLs mais caros
  • Instance Efficiency — buffer cache hit, redo log contention

3. ASH: visão em tempo real

O ASH (Active Session History) é fundamental para problemas que estão acontecendo agora:

-- Sessions com mais wait nos últimos 5 minutos
SELECT sql_id, event, COUNT(*) AS amostras
FROM v$active_session_history
WHERE sample_time > SYSDATE - 5/1440
GROUP BY sql_id, event
ORDER BY amostras DESC
FETCH FIRST 10 ROWS ONLY;

4. Identificar o SQL problemático

Com o sql_id em mãos:

-- Ver o texto completo
SELECT sql_fulltext
FROM v$sql
WHERE sql_id = '&sql_id';

-- Ver plano de execução atual
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));

Os sinais de alerta no plano:

  • FULL TABLE SCAN em tabelas grandes sem filtro seletivo
  • NESTED LOOPS com BUFFER SORT em volumes altos
  • Estimativas de cardinalidade muito distantes da realidade (sinal de estatísticas desatualizadas)

5. Estatísticas

Estatísticas desatualizadas são causa frequente de planos ruins:

-- Verificar quando foram coletadas pela última vez
SELECT table_name, last_analyzed, num_rows
FROM dba_tables
WHERE owner = 'MEU_SCHEMA'
ORDER BY last_analyzed ASC NULLS FIRST;

Se uma tabela de milhões de linhas não tem estatísticas há semanas, coleta imediata:

EXEC DBMS_STATS.GATHER_TABLE_STATS('MEU_SCHEMA', 'MINHA_TABELA', cascade => TRUE);

Conclusão

A ordem importa: confirmar o problema → AWR para contexto histórico → ASH para tempo real → SQL problemático → plano de execução → estatísticas. Pular etapas gera diagnósticos errados e soluções que não resolvem nada.