quinta-feira, 17 de maio de 2012

Redimensionamento ou recriando os arquivos de “Redo Log”


Neste artigo, irei demonstrar como redimensionar os arquivos de “redo logs”, neste exemplo os arquivos de “redo logs” serão redimensionados de 100 MB para 250 MB.


Porém, antes vamos verificar os grupos existentes no banco de dados e seus respectivos tamanhos.


SQL> SELECT a.group#, a.member, b.bytes
  2  FROM v$logfile a, v$log b 
  3  WHERE a.group# = b.group#;


    GROUP# MEMBER                        BYTES
---------- ----------------------------- ------------
         1 /u03/oradata/redo_g01a.log     104,857,600
         1 /u04/oradata/redo_g01b.log     104,857,600
         1 /u05/oradata/redo_g01c.log     104,857,600
         2 /u03/oradata/redo_g02a.log     104,857,600
         2 /u04/oradata/redo_g02b.log     104,857,600
         2 /u05/oradata/redo_g02c.log     104,857,600
         3 /u03/oradata/redo_g03a.log     104,857,600
         3 /u04/oradata/redo_g03b.log     104,857,600
         3 /u05/oradata/redo_g03c.log     104,857,600


9 rows selected.




Agora vamos verificar os passos para redimensionar ou recriar todos os grupos de “redo log”:


1. Verificar o status do grupo de “redo log”


Deve-se forçar um “switch” do “redo log” até que o último "redo log" permaneça marcado com o status de “CURRENT”, para executar esse passo usar o comando abaixo:


Verificação dos status dos grupos de “redo logs”.


SQL> select group#, status from v$log;


    GROUP# STATUS
---------- ----------------
         1 CURRENT
         2 INACTIVE
         3 INACTIVE




Execução do “switch” dos “redo logs”.


SQL> alter system switch logfile;


SQL> alter system switch logfile;




Nova verificação dos status dos grupos de “redo logs”.


SQL> select group#, status from v$log;


    GROUP# STATUS
---------- ----------------
         1 INACTIVE
         2 INACTIVE
         3 CURRENT


2. Remover o primeiro grupo de "redo log"


Depois de fazer o “switch” dos grupos de “redo logs”, já poderemos remover o primeiro grupo, para execução desta tarefa usar:




SQL> alter database drop logfile group 1;


Database altered.


NOTA: Algumas vezes, durante o processo de remoção o grupo de “redo log” poderá apresentar a mensagem de erro abaixo:


SQL> ALTER DATABASE DROP LOGFILE GROUP 1;
ALTER DATABASE DROP LOGFILE GROUP 1
*
ERROR at line 1:
ORA-01624: log 1 needed for crash recovery of instance tests (thread 1)
ORA-00312: online log 1 thread 1: ''


Isso poderá ocorrer porque o banco de dados não realizou um “checkpoint” automaticamente para liberar os grupos de “redo logs”.


Para resolver o problema, deve-se executar manualmente um “checkpoint” no banco de dados para que o “redo log” possa ser liberado para remoção, usando o comando abaixo:


SQL> ALTER SYSTEM CHECKPOINT GLOBAL;


3. Recriar o grupo de “redo log” que foi removido


Para recriar o grupo de “redo log” com o tamanho de 250 MB, deve-se executar o comando abaixo:


SQL> alter database add logfile group 1 (
  2  '/u03/oradata/redo_g01a.log',  
  3  '/u04/oradata/redo_g01b.log',
  4  '/u05/oradata/redo_g01c.log') size 250m reuse;


Database altered.


4. Forçar um novo “switch” no “redo log”


Depois de recriar o grupo, deve-se forçar um “switch” do “redo log”. O grupo de “redo log” que acabou de ser criado deverá apresentar o status “CURRENT”.


Verificação dos status dos grupos de “redo logs”, nesta verificação nota-se que o grupo 1 de “redo log”, ainda está com o status “UNUSED”, isso se deve porque esse grupo ainda não foi utilizado pelo banco de dados.


SQL> select group#, status from v$log;


    GROUP# STATUS
---------- ----------------
         1 UNUSED
         2 INACTIVE
         3 CURRENT




Execução do “switch” dos “redo logs”.


SQL> alter system switch logfile;




Nova verificação dos status dos grupos de “redo logs”.


SQL> select group#, status from v$log;


    GROUP# STATUS
---------- ----------------
         1 CURRENT
         2 INACTIVE
         3 ACTIVE


5. Continue a executar os passos de (1 a 4) até que todos os “redo logs” tenham sido recriados.


Após a recriação de um grupo de “redo log”, continue a recriar (ou redimensionar) todos os grupos de “redo logs” até que todos os grupos sejam recriados, na sequência deve-se revalidar os novos tamanhos dos “redo logs”.


SQL> SELECT a.group#, a.member, b.bytes
  2    FROM v$logfile a, v$log b 
  3   WHERE a.group# = b.group#;


    GROUP# MEMBER                         BYTES
---------- ------------------------------ ------------
         1 /u03/oradata/redo_g01a.log     262,144,000
         1 /u04/oradata/redo_g01b.log     262,144,000
         1 /u05/oradata/redo_g01c.log     262,144,000
         2 /u03/oradata/redo_g02a.log     262,144,000
         2 /u04/oradata/redo_g02b.log     262,144,000
         2 /u05/oradata/redo_g02c.log     262,144,000
         3 /u03/oradata/redo_g03a.log     262,144,000
         3 /u04/oradata/redo_g03b.log     262,144,000
         3 /u05/oradata/redo_g03c.log     262,144,000


9 rows selected.




Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com

terça-feira, 1 de maio de 2012

Como resolver problemas com transações Two-Phase-Commit 2/2


Na segunda parte deste artigo apresentaremos como resolver transações distribuídas que não possuam entradas correspondentes na visão DBA_2PC_PENDING e como “limpar” transações distribuídas que estão com status de PREPARED.

SOLUÇÕES
TRANSAÇÕES DISTRIBUÍDAS SEM ENTRADAS CORRESPONDENTES NA VISÃO DBA_2PC_PENDING
Neste caso as visões DBA_2PC_PENDING estão vazias, mas os usuários estão recebendo erros relacionados a transações distribuídas, por exemplo, os erros ORA-2054, ORA-1591.
Normalmente este caso não deve aparecer porem caso seja reproduzível pode ser um “BUG”, deve-se após resolver o problema, verificar no Oracle Support Metalink a atualização de “patches” para a correção da causa do problema. Abaixo são apresentadas algumas soluções de contorno:

  1. Limpar os objetos referenciados por essa transação e importá-las;
  2. Utilizar o parâmetro “_corrupted_rollback_segments” para descartar o segmento de rollback que esteja com problema;
  3. Inserir dados fictícios na visão DBA_2PC_PENDING para a execução de “commit ou rollback” (FORCE).

Para a solução 3 deve-se inserir dados fictícios no dicionário para que a transação possa ser confirmada ou revertida manualmente.

Observe que o banco de dados não será capaz de processar esta transação distribuída e o processo (RECO) deve ser desativado antes de usar este método (deve-se desabilitar o modo de arquivamento automático “archive log mode”).

Importante: Realizar um BACKUP do seu banco de dados antes de usar este método.
Transações que ficaram presas são a causa do erro ORA-01591, por isso a necessidade de limpar essas entradas, deve-se utilizar a package DBMS_TRANSACTION.

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('id_da_transacao');

O exemplo a seguir descreve como diagnosticar e resolver este caso. Suponha que  os usuários estão recebendo a mensagem abaixo:

ORA-1591: lock held by in-doubt distributed transaction 1.92.66874.
E a consulta abaixo não retorne linhas.
SQL> select local_tran_id, state
       from dba_2pc_pending
      where local_tran_id='1.92.66874';

no rows selected

Além disso, ao consultar o segmento de “undo”  é apresentada a transação “1.92.66874” que está em modo PREPARED.

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
            KTUXESTA Status, KTUXECFL Flags
       FROM x$ktuxe
      WHERE ktuxesta!='INACTIVE'
        AND ktuxeusn= 1;  /* <== Substituir este valor pelo
                                 número do segmento de rollback
                                 de sua transação */

SQL> KTUXEUSN   KTUXESLT   KTUXESQN   STATUS           FLAGS
     ---------- ---------- ---------- ---------------- --------------------
     1          92         66874      PREPARED         SCO|COL|REV|DEAD

E se realiza uma tentativa de realizar um “commit force” ou “rollback force” desta transação.
SQL> commit force '1.92.66874';
ORA-02058: no prepared transaction found with ID 1.92.66874
O erro ORA-02058 são gerados porque as visões DBA_2PC_PENDING e DBA_2PC_NEIGHBORS estão vazias. Para usar o “commit force” ou “rollback force” deve-se inserir um registro fictício na visão DBA_2PC_PENDING, conforme apresentado abaixo:

SQL> alter system disable distributed recovery;

SQL> insert into pending_trans$ ( LOCAL_TRAN_ID, GLOBAL_TRAN_FMT, GLOBAL_ORACLE_ID,
STATE, STATUS, SESSION_VECTOR, RECO_VECTOR,TYPE#, FAIL_TIME, RECO_TIME)
values( '1.92.66874',    /* Altere o valor de sua transação local (LOCAL_TRAN_ID)  */
306206,                  /*                                                      */
'XXXXXXX.12345.1.2.3',   /* Esses valores podem ser utilizados sem qualquer      */
'prepared','P',          /* modificação. Muitos desses valores sáo constantes    */
hextoraw( '00000001' ),  /*                                                      */
hextoraw( '00000000' ),  /*                                                      */
0, sysdate, sysdate );

SQL> insert into pending_sessions$
values( '1.92.66874',   /* <==Altere para sua transação local (LOCAL_TRAN_ID)*/
1, hextoraw('05004F003A1500000104'), 'C', 0, 30258592, '', 146);
SQL> commit;

SQL> commit force '1.92.66874';

Se a instrução “commit force” gerar um erro, anote a mensagem de erro e execute os comandos abaixo:

SQL> delete from pending_trans$ where local_tran_id='1.92.66874';
SQL> delete from pending_sessions$ where local_tran_id='1.92.66874';
SQL> commit;
SQL> alter system enable distributed recovery;

Caso contrário executar o processo de entrada fictícia do dicionário, usando:

SQL> alter system enable distributed recovery;
SQL> connect / as sysdba
SQL> COMMIT;

Use a consulta abaixo para recuperar o valor para do parâmetro “_smu_debug_mod”.

SQL> col Parameter for a20
SQL> col "Session Value" for a20
SQL> col "Instance Value" for a20

SQL> SELECT a.ksppinm "Parameter",b.ksppstvl "Session Value",
            c.ksppstvl "Instance Value"
       FROM x$ksppi a, x$ksppcv b, x$ksppsv c
      WHERE a.indx = b.indx
        AND a.indx = c.indx
        AND a.ksppinm = '_smu_debug_mode';

Configure o parâmetro “_smu_debug_mode” para 4.

SQL> alter system  set "_smu_debug_mode" = 4; 
           /* Configurar com esse valor se estiver usando
              o segmento de UNDO em modo automático */

A partir da versão 9.2x o comando “alter session” pode ser utilizado dinamicamente.

SQL> commit;  /* Isto é para evitar o erro ORA-01453 durante a
                 limpeza utilizando a package “purge_lost_db_entry” */

SQL> exec dbms_transaction.purge_lost_db_entry( '1.92.66874' );

SQL> commit;

SQL> alter system set "_smu_debug_mode" = ;

SQL> commit;

COMO LIMPAR UMA TRANSAÇÃO DISTRIBUÍDA COM “STATUS” PREPARED, QUANDO UM COMMIT OU ROLLBACK FORCE, TRAVAR.

Se a mensagem abaixo for apresentada.
ORA-01591: lock held by in-doubt distributed transaction 44.88.85589

Deve-se verificar se o registro existe na visão DBA_2PC_PENDING e qual o segmento de “rollback” está em uso, execuntando o comando abaixo.

SQL> SELECT LOCAL_TRAN_ID,STATE FROM DBA_2PC_PENDING;
LOCAL_TRAN_ID   STATE
--------------  --------
44.88.85589     prepared


SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
            KTUXESTA Status, KTUXECFL Flags
       FROM x$ktuxe
      WHERE ktuxesta!='INACTIVE'
        AND ktuxeusn= 44; /* <== Alterar o valor para o número da transação
                                 no seu segmento de UNDO que é exibido na
                                 primeira parte do ID da transação */

KTUXEUSN   KTUXESLT   KTUXESQN   STATUS           FLAGS
---------- ---------- ---------- ---------------- ------------------------
44         88         85589      PREPARED         SCO|COL|REV|DEAD


SQL> Commit force 44.88.85589;

ou

SQL> rollback force 44.88.85589;

Se ao executar o “COMMIT” ou “ROLLBACK FORCE” e o comando travar, o banco de dados irá assinalar o evento de espera (wait system events)  "free global transaction table entry”.

Para limpar esta transação, deve-se utilizar a package abaixo:
SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('44.88.85589');
BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('44.88.85589'); END;

*
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYS.DBMS_TRANSACTION", line 94
ORA-06512: at line 1

Caso essa mensagem de erro apareça pode-se executar umas das soluções:


1.   Gerar entradas de dados nas visões das DBA_2PC_PENDING e DBA_2PC_NEIGHBORS sem transações correspondentes;
2.   Gerar transações distribuídas sem entradas correspondentes nas visões DBA_2PC_PENDING e DBA_2PC_NEIGHBORS

Para a solução 1, executar os comandos abaixo:

SQL> delete from sys.pending_trans$ where local_tran_id = '44.88.85589';
SQL> delete from sys.pending_sessions$ where local_tran_id = '44.88.85589';
SQL> delete from sys.pending_sub_sessions$
      where local_tran_id ='44.88.85589';
SQL> commit;


Para a solução 2, executar os passos abaixo:

Inserir registros fictícios, como descritos na seção (ver: Transações distribuídas sem entradas correspondentes na visão DBA_2PC_PENDING). Para transações distribuídas sem registros correspondentes na visão DBA_2PC_PENDING, executar.

SQL> Commit force '44.88.85589';

Para limpar transações pendentes, usar:

SQL> exec dbms_transaction.purge_lost_db_entry('44.88.85589');


Para escrever esse artigo usei como referência a nota da Oracle (Note:126069.1 -  Manually Resolving In-Doubt Transactions: Different Scenario's).


Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com