Pode haver ocasiões em que seja necessário investigar alterações recentes no banco de dados e relatar o que foi alterado, quando e por quem. Durante anos, o pacote DBMS_LOGMNR da Oracle esteve disponível para essas tarefas, mas suas invocações não foram totalmente cobertas. Os métodos convencionais usam o procedimento ADD_LOGFILE() para preparar o Log Miner para uso com uma chamada básica para o procedimento START_LOGMNR. Isso inicia o utilitário com o SCN atual como ponto de partida. Há outra maneira de iniciar o Log Miner, selecionando um SCN inicial válido e fornecendo isso para a chamada START_LOGMNR(). Neste artigo, você verá como isso pode ser feito e, no processo, revelará uma possível área de preocupação com alocações de PGA.
Olhando para um script 'plain vanilla' para iniciar o Log Miner, as chamadas de procedimento usuais são feitas que iniciam o Log Miner com o SCN atual:
---- run_logmnr.sql---- Adicionar arquivos de log e definir DBMS_LOGMNR para-- minerar continuamente archivelogs--definir tamanho de linha 200 trimspool no tamanho de página 0---- Adicionar os arquivos de log existentes---- Omitir arquivos de log em espera- -selecione 'exec dbms_logmnr.add_logfile('''||member||''')'de v$logfilewhere digite <> 'STANDBY'and member in (select min(member) from v$logfile group by group#)spool /tmp/add_logfiles.sql/spool off@/tmp/add_logfiles---- Iniciar logmnr no modo de mina contínua--exec dbms_logmnr.start_logmnr(options => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.CONTINUOUS_MINE + DBMS_LOGMNR.COMMITTED_DATA_ONLY)
Observe que todos os redo logs disponíveis são adicionados antes de iniciar o Log Miner. Existe outro método que fornece um SCN inicial para a chamada start_logmnr, desde que o banco de dados esteja sendo executado no modo ARCHIVELOG:
BEGIN DBMS_LOGMNR.START_LOGMNR( startScn =>, endScn => , OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.COMMITTED_DATA_ONLY + DBMS_LOGMNR.CONTINUOUS_MINE);END;/
Curiosamente, o SCN final não é necessário para iniciar uma sessão do Log Miner. O banco de dados deve estar no modo ARCHIVELOG para que a opção CONTINUOUS_MINE possa ser especificada porque o Log Miner adicionará automaticamente todos os arquivos de log arquivados disponíveis durante a execução. O uso desse método permite que um SCN específico seja usado para iniciar qualquer pesquisa; especificando a pesquisa final de colchetes SCN para que apenas um subconjunto limitado de dados seja retornado para a visualização V$LOGMNR_CONTENTS e forneça um ponto de parada para a pesquisa, para que uma consulta da visualização possa terminar.
É uma tarefa simples monitorar o progresso do Log Miner verificando o log de alerta do banco de dados à medida que as entradas marcadas com 'LOGMINER' são registradas. Uma entrada completa incluirá uma linha BEGIN e END, conforme mostrado abaixo:
Seg 07 de outubro 12:48:22 2019LOGMINER:Finalizar arquivo de log de mineração para sessão -2147482111 thread 1 sequência 9776, /oracle/archive/awcis/awcis_0000009776_0001_1008544071.arcMon Out 07 12:48:22 2019LOGMINER:Iniciar arquivo de log de mineração para sessão - 2147482111 thread 1 sequence 9777, /oracle/archive/awcis/awcis_0000009777_0001_1008544071.arcMon Oct 07 12:48:36 2019LOGMINER:End mining logfile for session -2147482111 thread 1 sequence 9777, /oracle/archive/awcis/awcis_0000009777_0001_1008544071.arcMon Oct 07 12 :48:36 2019LOGMINER:Iniciar o arquivo de log de mineração para a sessão -2147482111 thread 1 sequence 9778, /oracle/archive/awcis/awcis_0000009778_0001_1008544071.arcMon Oct 07 12:48:49 2019LOGMINER:Finalizar o arquivo de log de mineração para a sessão -2147482111 thread oracle/archive/awcis/awcis_0000009778_0001_1008544071.arcMon Oct 07 12:48:49 2019LOGMINER:Comece a mineração do arquivo de log para a sessão -2147482111 thread 1 sequence 9779, /oracle/archive/awcis/awcis_0040009779_pre
Para sessões locais do Oracle, os números são inteiros positivos; para sessões remotas, iniciadas por utilitários como Perl, Python, C/C++ ou outras linguagens, inteiros negativos serão vistos (as entradas mostradas acima foram iniciadas por um script Python). Os nomes dos arquivos de log passarão pelos redo logs online e pelas cópias arquivadas disponíveis.
Iniciar o Log Miner dessa forma também pode gerar erros como 'arquivo de log ausente' quando o SCN inicial selecionado ou o intervalo SCN não estiver mais disponível no fluxo de redo. Consultas de longa duração podem encontrar esses erros. Além disso, se o SCN estiver fora do intervalo em relação aos arquivos de log disponíveis, o Log Miner não será iniciado, lançando:
ERRO na linha 1:ORA-01292:nenhum arquivo de log foi especificado para a sessão atual do LogMinerORA-06512:em "SYS.DBMS_LOGMNR", linha 58ORA-06512:na linha 2
Para ajudar a eliminar tais erros, selecionar FIRST_CHANGE# na visualização V$LOG fornecerá pontos de partida válidos para uma sessão do Log Miner; usar uma consulta semelhante em V$ARCHIVED_LOG retornará todos os SCNs iniciais disponíveis para as cópias de redo arquivadas.
Essa não é a única complicação de usar o Log Miner dessa maneira. Dependendo da quantidade de informações a serem retornadas, o processo Logminer pode alocar grandes quantidades de memória PGA que pode, se o pga_aggregate_limit for pequeno, gerar o seguinte erro:
ORA-04036:a memória PGA usada pela instância excede PGA_AGGREGATE_LIMIT
felizmente este não é um erro fatal. Como os recursos PGA não são mais necessários, a memória pode ser liberada de volta ao banco de dados para uso em outro lugar. No entanto, pode demorar um pouco mais do que o desejado para que a memória seja liberada de volta ao pool de memória. Uma opção é definir o pga_aggregate_limit maior que a soma das sessões do Log Miner, o que pode evitar que o erro ocorra. Como você sabe qual memória está alocada para essas sessões? Uma visão, V$PROCESS_MEMORY_DETAIL, está disponível no banco de dados. Mas tentar consultar essa visão sem alguma preparação retornará:
nenhuma linha selecionada.
Este é um problema relativamente pequeno, mas requer o uso do utilitário oradebug. As etapas a seguir carregarão os dados em V$PROCESS_MEMORY_DETAIL:
---- Defina o identificador de sessão atual-- oradebug setmypid---- Usando o PID do processo desejado-- despeje os dados da memória---- Isso preenche V$PROCESS_MEMORY_DETAIL--oradebug pga_detail_get- --- Consulte a visualização para obter os dados desejados--selecione * From v$process_memory_detail;---- Para repovoar a visualização com dados mais recentes-- basta executar a instrução oradebug pga_detail_get----oradebug pga_detail_get
Um script para executar essas ações é mostrado abaixo:
---- Configurar o ambiente para chamadas oradebug--oradebug setmypidset echo off trimspool onset check offundefine p_1undefine p_2undefine s1undefine s2variable p1 numbervariable p2 numbercolumn sys_date new_value sysdt noprintselect to_char(sysdate, 'RRRRMMDDHH24MISS') sys_date from dual;-- -- Obtém o id do processo da sessão--column pid new_value p_1select pid from v$process where addr in (selecione paddr from v$session onde username =' ' e sid =(selecione max(sid) From v$session where username =' '));begin :p1 :=&p_1;end;/---- Despejar detalhes do processo para v$process_memory_detail--oradebug dump pga_detail_get &p_1spool &p_1._pga_stats_&sysdt..log--- - Obter informações de sessão para --COLUMN alme HEADING "MB Alocado" FORMAT 99999D9COLUMN usme HEADING "MB usado" FORMAT 99999D9COLUMN frme HEADING "MB livre" FORMAT 99999D9COLUMN mame HEADING "Max MB" FORMAT 99999D9COLUMN nome de usuário FORMAT a25COLUMN program FORMAT a22COLUMN sid FORMAT a5COLUMN spid FORMAT a8coluna pid_remote formato a12SET LINESIZE 300SELECT s.username, SUBSTR(s.sid,1,5) sid, p.spid, logon_time, SUBSTR(s.program,1,22) program , s.process pid_remote, s.status, ROUND(pga_used_mem/1024/1024) usme, ROUND(pga_alloc_mem/1024/1024) alme, ROUND(pga_freeable_mem/1024/1024) frme, ROUND(pga_max_mem/1024/1024) mameFROM v$session s, v$process pWHERE p.addr=s.paddrAND s.username =' 'ORDER BY pga_max_mem,logon_time;---- Sleep 30 segundos---- Obter informações da sessão novamente--exec dbms_lock.sleep(30) coluna sid new_value s1 noprintSELECT s.username, SUBSTR(s.sid,1,5) sid, p.spid, logon_time, SUBSTR(s.program,1,22) program , s.process pid_remote, s.status, ROUND( pga_used_mem/1024/1024) usme, ROUND(pga_alloc_mem/1024/1024) alme, ROUND(pga_freeable_mem/1024/1024) frme, ROUND(pga_max_mem/1024/1024) mameFROM v$session s,v$process pWHERE p.addr=s.paddrAND s.username =' 'ORDER BY pga_max_mem,logon_time;exec dbms_lock.sleep(10)select max(sid) sid from v$session where username =' ';---- Obter informações da memória do processo--COLUMN category HEADING "Category"COLUMN alocado HEADING "Alocados bytes"COLUMN usados HEADING "Usados bytes"COLUMN max_allocated HEADING "Max alocados bytes"SELECT pid, category, alocado, usado, max_allocatedFROM v$process_memoryWHERE pid in (SELECT pid FROM v$process WHERE addr in (selecione paddr FROM v$session WHERE sid =&&s1));exec dbms_lock.sleep(10)SELECT pid, categoria, alocado, usado, max_allocatedFROM v$process_memoryWHERE pid in (SELECT pid FROM v$process WHERE addr in (selecione paddr FROM v$session WHERE sid =&&s1));exec dbms_lock.sleep(10)select pid from v$process whe re addr in (selecione paddr de v$session onde nome de usuário =' ' e sid =(selecione max(sid) de v$session onde nome de usuário =' ')); ---- Salve a primeira passagem de pga stats--CREATE TABLE tab1 ASSELECT pid, category, name, heap_name, bytes, alocation_count, heap_descriptor, parent_heap_descriptorFROM v$process_memory_detailWHERE pid =&p_1AND category ='Other';---- Obtém a segunda passagem de pga stats--oradebug dump pga_detail_get &p_1exec dbms_lock.sleep(120)---- Salva a segunda passagem de pga stats--CREATE TABLE tab2 ASSELECT pid, category, name, heap_name, bytes,location_count, heap_descriptor, parent_heap_descriptorFROM v$process_memory_detailWHERE pid =&p_1AND category ='Other'; ---- Iniciar relatórios finais---- PGA heap info--COLUMN category HEADING "Category"COLUMN name HEADING "Nome"COLUMN heap_name HEADING "Heap name"COLUMN q1 HEADING "Memory 1st" Formato 999.999.999.999COLUMN q2 HEADING "Memory 2nd " Formato 999.999.999,9 99COLUMN diff TÍTULO "Diferença" Formato S999.999.999.999SET LINES 150SELECT tab2.pid, tab2.category, tab2.name, tab2.heap_name, tab1.bytes q1, tab2.bytes q2, tab2.bytes-tab1.bytes diffFROM tab1, tab2WHERE tab1.category =tab2.categoryAND tab1.name =tab2.nameAND tab1.heap_name =tab2.heap_nameand tab1.pid =tab2.pidAND tab1.bytes <> tab2.bytesORDER BY 1, 7 DESC;---- Logminer PGA info- -COLUMN heap_name HEADING "nome do heap"COLUMN name HEADING "Tipo"COLUMN alocação_count HEADING "Contagem"COLUMN bytes TÍTULO "Soma"COLUMN avg TÍTULO "Média" FORMAT 99999D99SELECT pid, heap_name, nome, alocação_count, bytes, bytes/allocation_count avgFROM tab2WHERE heap_name como 'Logminer%';spool offdrop table tab1 purge;drop table tab2 purge;
Salve este código como um script e edite o texto para substituir as stringspela conta de usuário que executa o Log Miner. O script visa especificamente a memória do Logminer para que possa ser monitorado quanto a aumentos. Ele também pode ser modificado para procurar outras áreas de memória com problemas. Comente os comandos 'soltar tabela' para preservar tab1 e tab2 para pesquisas adicionais, se desejar, pois outras áreas de memória podem ser de interesse. Verifique também o suporte da Oracle para problemas conhecidos relacionados a PGA. Esses relatórios provavelmente terão consultas para investigar áreas problemáticas específicas usando V$PROCESS_MEMORY_DETAIL. Por conveniência, essas consultas adicionais podem ser adicionadas ao código mostrado acima para relatar todas as áreas suspeitas da memória do processo. Esses dados serão fundamentais para comprovar a necessidade de aplicação de patches pontuais específicos ao banco de dados.
O Log Miner pode ser uma ferramenta muito útil na investigação de ações passadas atuais e relativamente recentes no banco de dados. Pode ser necessário monitorar as alocações de PGA enquanto as sessões do Log Miner estiverem ativas para que ações preventivas, como aumentar o pga_aggregate_limit, possam ser executadas e as sessões não sejam encerradas abruptamente. “Prevenido é preparado”, como diz o ditado, e mesmo que os DBAs não tenham quatro braços saber o que pode vir pela frente é sempre um conhecimento que vale a pena ter.
Veja todos os artigos de David Fitzjarrell