12c

Ola pessoal. Segue mais um artigo sobre o Oracle 12c. Dessa vez eu brinquei um pouco com a feature de RECOVER TABLE do RMAN, feature essa que foi uma das mais anunciadas pela Oracle. Essa feature facilita e muito a vida do DBA que precisa realizar o restore de apenas uma ou poucas tabelas corrompidas/truncadas “acidentalmente”. Ela nada mais é do que um Tablespace Point-in-time recovery mais automático, e como consequência disso, menos suscetível a erros.

 

Conceitos iniciais

Para realizar o RECOVER de uma tabela específica, o RMAN cria uma base de dados auxiliar (auxiliary instance) para ser usada durante o recover. O destino dessa base de dados auxiliar é definido pelo comando AUXILIARY DESTINATION. Depois da base ter sido criada, o RMAN realiza um export da tabela dessa base auxiliar e importa seus dados na base principal, via Datapump.

A base auxiliar restaura as tablespaces SYSTEM, SYSAUX, UNDO, SYSEXT (caso presente), e as tablespaces que contenham as tabelas a serem restauradas, portando, deve-se verificar antes do restore, se há espaço suficiente para armazenar essa instância auxiliar (soma das tablespaces SYSTEM, SYSAUX, UNDO, SYSEXT e tablespaces das tabelas a serem restauradas)

O RECOVER TABLE permite recuperar uma ou varias tabelas até um certo sequence#, SCN ou período de tempo – UNTIL [SEQUENCE|SCN|TIME] respectivamente.

A tabela usada para testes foi a seguinte:

   —
   — depois de criar essa tabela, povoei ela com 100.000 registros
   —

CREATE TABLE USR_PROD.TAB_TESTES_RECOVER (
ID_REGISTRO   NUMBER CONSTRAINT PK_ID_REG_TST_RECOVER PRIMARY KEY,
DESCRICAO     VARCHAR2(200),
CODIGO        NUMBER CONSTRAINT UK_CODIGO_01 UNIQUE,
DATA_REG      DATE
);

 

Pré-requisitos

– Banco de dados deve estar em ARCHIVELOG

– Pelo menos um backup FULL das tablespaces SYSTEM, SYSAUX, UNDO, SYSEXT (caso presente), e as tablespaces que contenham as tabelas a serem restauradas, mais os archives até o período desejado de restore.

– Espaço suficiente para armazenar a instância auxiliar

– Caso a tabela a ser recuperada possua dependentes (child tables), estas também devem ser incluídas no RECOVER.

– O RECOVER deve ser executado a partir do Container.

– Case a tabela a ser recuperada esteja em um PDB, deve-se especificar a clausula OF PLUGGABLE DATABASE <nome_pdb>

 

Exemplos

   —
   — EX01 – recuperando uma tabela que existia anteriormente dentro do CDB
   —

RMAN> RECOVER TABLE USR_PROD.TAB_TESTES_RECOVER UNTIL SEQUENCE 165 AUXILIATY DESTINATION '/backup/auxiliary';

 

   —
   — EX02 – recuperando uma tabela que existia anteriormente dentro de um determinado PDB
   — nesse caso, deve-se usar a clausula OF PLUGGABLE DATABASE <nome_pdb>
   —

RMAN> RECOVER TABLE USR_PROD.TAB_TESTES_RECOVER OF PLUGGABLE DATABASE PDBPROD1 UNTIL SEQUENCE 34 AUXILIARY DESTINATION '/aux/auxiliary';

  

   —
   — EX03 – recuperando uma tabela que existia anteriormente dentro de um determinado PDB
   — neste exemplo além de realizar o recover, também remapeei a tabela e a tablespace destino
   —

RMAN> RECOVER TABLE USR_PROD.TAB_TESTES_RECOVER OF PLUGGABLE DATABASE PDBPROD1
UNTIL SEQUENCE 34
AUXILIARY DESTINATION '/flash_recovery_area/auxiliary'
REMAP TABLE 'USR_PROD'.'TAB_TESTES_RECOVER':'TAB_TESTES_RECOVER_OLD'
REMAP TABLESPACE 'TBS_PROD':'TBS_RECOVERED';

  

   —
   — EX04 – recuperando uma tabela que existia anteriormente dentro de um determinado PDB
   — neste exemplo, eu não realizei de fato a restauração da tabela, mas apenas gerei o
   — dump necessario (clausulas DATAPUMP DESTINATION e DUMP FILE)
   — para realizar o import dessa tabela em qualquer base de dados.
   — a clausula NOTABLEIMPORT é quem define que a tabela não será restaurada
   —

RMAN> RECOVER TABLE USR_PROD.TAB_TESTES_RECOVER OF PLUGGABLE DATABASE PDBPROD1
UNTIL SEQUENCE 34
AUXILIARY DESTINATION '/aux/auxiliary'
DATAPUMP DESTINATION '/aux/auxiliary'
DUMP FILE 'impdp_tab_testes_recover_19052014.dmp'
NOTABLEIMPORT;

… vejam que após o término da execução do comando acima, eu tenho meu dump, como havia definido na clausula DUMP FILE:

drwxr-x---. 5 oracle oinstall 4.0K May 19 17:29 DB12
drwxr-x---. 4 oracle oinstall 4.0K May 19 17:44 GATG_PITR_PDBPROD1_DB12
      -rw-r-----. 1 oracle oinstall 4.0K May 19 17:46 impdp_tab_testes_recover_19052014.dmp

… após gerar o dump, a instância auxiliar é removida (assim como em todas as operações acima):

     Not performing table import after point-in-time recovery
    
     Removing automatic instance
     shutting down automatic instance
     Oracle instance shut down
     Automatic instance removed
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_temp_9qnv6gl0_.tmp deleted
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_temp_9qnv5rf5_.tmp deleted
     auxiliary instance file /aux/auxiliary/GATG_PITR_PDBPROD1_DB12/onlinelog/o1_mf_3_9qnv9z2k_.log deleted
     auxiliary instance file /aux/auxiliary/GATG_PITR_PDBPROD1_DB12/onlinelog/o1_mf_2_9qnv9t5z_.log deleted
     auxiliary instance file /aux/auxiliary/GATG_PITR_PDBPROD1_DB12/onlinelog/o1_mf_1_9qnv9o99_.log deleted
     auxiliary instance file /aux/auxiliary/GATG_PITR_PDBPROD1_DB12/datafile/o1_mf_tbs_prod_9qnv7k40_.dbf deleted
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_sysaux_9qntl4ry_.dbf deleted
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_system_9qntl4w0_.dbf deleted
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_sysaux_9qntdonc_.dbf deleted
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_undotbs1_9qntofvp_.dbf deleted
     auxiliary instance file /aux/auxiliary/DB12/datafile/o1_mf_system_9qntdomg_.dbf deleted
     auxiliary instance file /aux/auxiliary/DB12/controlfile/o1_mf_9qntd8mf_.ctl deleted     

     Finished recover at 19-MAY-14

… como não confio muito nas coisas, gerei o arquivo DDL a partir do dump acima gerado, somente para ter certeza de que tudo foi bem:

impdp c##fabricio/<senha>@pdbprod1 directory=TSPITR_DIROBJ_DPDIR dumpfile=impdp_tab_testes_recover_19052014.dmp tables=USR_PROD.TAB_TESTES_RECOVER sqlfile=ddl_tabela.sql

… o comando acima me gerou um arquivo .sql contendo os DDLs do dump. Nele podemos ver que a tabela está lá bem como todas as suas costraints:

— new object type path: TABLE_EXPORT/TABLE/TABLE
CREATE TABLE "USR_PROD"."TAB_TESTES_RECOVER"
(    "ID_REGISTRO" NUMBER,
"DESCRICAO" VARCHAR2(200 BYTE),
"CODIGO" NUMBER,
"DATA_REG" DATE
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TBS_PROD" ;

— new object type path: TABLE_EXPORT/TABLE/INDEX/INDEX
— CONNECT USR_PROD
CREATE UNIQUE INDEX “USR_PROD”.”UK_CODIGO_01″ ON “USR_PROD”.”TAB_TESTES_RECOVER” (“CODIGO”)
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE “TBS_PROD” PARALLEL 1 ;

ALTER INDEX “USR_PROD”.”UK_CODIGO_01″ NOPARALLEL;
CREATE UNIQUE INDEX “USR_PROD”.”PK_ID_REG_TST_RECOVER” ON “USR_PROD”.”TAB_TESTES_RECOVER” (“ID_REGISTRO”)
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE “TBS_PROD” PARALLEL 1 ;
ALTER INDEX “USR_PROD”.”PK_ID_REG_TST_RECOVER” NOPARALLEL;

— new object type path: TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
— CONNECT C##FABRICIO
ALTER TABLE “USR_PROD”.”TAB_TESTES_RECOVER” ADD CONSTRAINT “UK_CODIGO_01” UNIQUE (“CODIGO”)
USING INDEX “USR_PROD”.”UK_CODIGO_01″  ENABLE;
ALTER TABLE “USR_PROD”.”TAB_TESTES_RECOVER” ADD CONSTRAINT “PK_ID_REG_TST_RECOVER” PRIMARY KEY (“ID_REGISTRO”)
USING INDEX “USR_PROD”.”PK_ID_REG_TST_RECOVER”  ENABLE;