Overblog
Editer l'article Suivre ce blog Administration + Créer mon blog
LAMI DBA

Articles autour des SGBD Oracle, SQL Server & PostgreSQL

Oracle 12c Enterprise Multitenant : Sauvegarde et Restauration pluggable database avec RMAN

En 12c Enterprise, avec l'option Multitenant (container DB), Rman permet de sauvegarder 3 éléments distincts :

-La base container nommée "CDB",

-les pluggables databases "PDBs"

-les métadatas.

Dans cet article, nous allons étudier la partie Pluggable database, à mon sens la plus courante dans le monde de la production.

Pour cet exemple, l'OS utilisé est un system Linux (Oracle Linux 7).

Réalisons donc un backup complet de notre CDB qui inclut donc toutes les PDBs :

Petit passage en archivelog avant toutes choses :

SQL> alter system set log_archive_dest='/oradata/CDB/arch' scope=both ;
System altered.

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount ;
ORACLE instance started.
..
Database mounted.
SQL>alter database archivelog ;
Database altered.

SQL> alter database open;
Database altered.

SQL>alter pluggable database all open read write ;
Pluggable database altered.

SQL> archive log list;
Database log mode Archive Mode
Automatic archival Enabled
Archive destination /oradata/CDB/arch
Oldest online log sequence 208
Next log sequence to archive 210
Current log sequence 210

SQL> show pdbs

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
4 MYPDB1 READ WRITE NO

 

Go pour un petit backup full

RMAN> sql 'alter system switch logfile';

using target database control file instead of recovery catalog
sql statement: alter system switch logfile

RMAN> backup database format '/oratmp/Backup/bkpfull_svg_DB_on%_%t%U.bkp' plus archivelog ;

Starting backup at 18-SEP-15
current log archived
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=423 device type=DISK
channel ORA_DISK_1: starting archived log backup set
...
...
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:07
Finished backup at 18-SEP-15
...
Finished Control File and SPFILE Autobackup at 18-SEP-15

 

Ok, nous allons maintenant créer une petite panne "utilisateur" sur la PDB MYPDB1 :

SQL> alter session set container=MYPDB1;
Session altered.

SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
5296

SQL> delete from MRS_EXECUTED_BLOCKS;
5296 rows deleted
SQL> commit;
SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
0

 

Là, nous avons une simple erreur utilisateur... Deux choix s'offrent principalement à nous :

- La restauration complète de la PDB
ou
- La restauration incomplète, ou encore restauration d'une ou plusieurs tables dans le cas de cet article.

Voyons voir tout d'abord la restauration complète de la PDB dans laquelle se trouve la table ci dessus.

Note : Bien sur pour ce type d'opération, la PDB se doit d'être CLOSE.

RMAN> sql 'alter pluggable database MYPDB1 close immediate';

using target database control file instead of recovery catalog 

sql statement: alter pluggable database MYPDB1 close immediate

RMAN> run {
set until time "to_date('18-09-2015:08:50:00', 'DD-MM-YYYY:hh24:mi:ss')";
restore pluggable database MYPDB1;
recover pluggable database MYPDB1
AUXILIARY DESTINATION '/oratmp'; }

 

Note :
En restauration PITR (Point In Time Recovery), si la flash_recovery n'est pas configurée, l'utilisation du paramètre "AUXILIARY DESTINATION" est obligatoire pour effectuer le Recover.

Cette log est assez intéressante ... On s’aperçoit qu'RMAN va créer une instance temporaire "clone" de l'instance CDB pour effectuer ONLINE, sans aucun arrêt de l'instance principale (imaginons une prod), un recover en PITR de notre PDB.

Cela veut dire aussi en langage "stockage" qu'il faut prévoir du disque (soit unitairement comme l'exemple ci dessus, ou soit fixe pour une Flash_recovery), et cela peut monter vite en Go en fonction de la taille de notre PDB ..

RMAN> sql 'alter pluggable database MYPDB1 open resetlogs';
sql statement: alter pluggable database MYPDB1 open resetlogs

RMAN>exit;

/oratmp/CDB[CDB]:sqlplus / as sysdba

SQL*Plus: Release 12.1.0.2.0 Production on Fri Sep 18 09:20:33 2015

Copyright (c) 1982, 2014, Oracle. All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> set lines 200
SQL> select DBID,NAME,OPEN_MODE,OPEN_TIME from v$pdbs;

DBID NAME OPEN_MODE OPEN_TIME
---------- ------------------------------ ---------- ---------------------------------------------------------------------------
548741631 PDB$SEED READ ONLY 17-SEP-15 07.56.27.384 PM +02:00
888812708 MYPDB1 READ WRITE 18-SEP-15 09.20.02.391 AM +02:00

SQL> alter session set container=MYPDB1 ;
Session altered.

SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
5296

=> Ok, nous avons retrouvé nos datas, restauré uniquement notre PDB sans impact sur la dispo de l'instance CDB principale, et donc de facto sur les autres PDBs (dans le cas où nous en aurions eu plusieurs), mais nous avons quand même du générer une indisponibilité de la PDB cible.

Nous aurions pu donc passer par une restauration table uniquement, puisque RMAN (en 12c) permet la restauration d'une table directement !

Mais qu'allons nous faire de Datapump alors me direz vous ? Et bien le conserver, car il est toujours utile d'avoir un dump à coté au cas ou (par expérience, avec les joies de la robotique ..)

Note :
Attention, pour Datapump sur une PDB, il faut là encore utiliser un ALIAS TNS pour le réaliser, car un datapump full de la CDB ne permet en effet pas de réaliser un export des PDBs.

Vu que nous avons restauré la PDB, il faut re-simuler une panne, on refait donc un petit backup de notre PDB, avec une gestion des archivelogs car dans ce second exemple je vais utiliser le until sequence pour ainsi réaliser une restauration PITR.

SQL> alter session set container=cdb$root;
Session altered.

SQL> alter system switch logfile ;
System altered.

SQL> exit

RMAN> run {
backup pluggable database MYPDB1 format '/oratmp/Backup/bkpfull_MYPDB1_on%_%t%U.bkp' ;
backup archivelog all format '/oratmp/Backup/bkpfull_MYPDB1_ARCH_%t%U.bkp' ;
}

Starting backup at 18-SEP-15
using channel ORA_DISK_1
...
...
...
Finished Control File and SPFILE Autobackup at 18-SEP-15

RMAN> exit

-> On génère une petite archivelog histoire de nous arrêter à la précédente

/home/oracle[CDB]:sqlplus / as sysdba

SQL*Plus: Release 12.1.0.2.0 Production on Fri Sep 18 09:25:55 2015

Copyright (c) 1982, 2014, Oracle. All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> alter system switch logfile ;
System altered.

SQL> select sequence#,to_char(completion_time,'DD-MM-YYYY HH24:MI:SS') from v$archived_log where to_char(completion_time,'DD-MM-YYYY HH24:MI:SS') > '18-09-2015 10:10:00';

SEQUENCE# TO_CHAR(COMPLETION_
---------- -------------------
370 18-09-2015 10:15:51
371 18-09-2015 10:16:29
372 18-09-2015 10:16:50
373 18-09-2015 10:17:31
374 18-09-2015 10:18:41

SQL> alter session set container=MYPDB1 ;
Session altered.

SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
5296

SQL> delete from "MYPDB1"."MRS_EXECUTED_BLOCKS";
5296 rows deleted.

SQL> commit;
Commit complete.

==> Lançons donc notre restauration de cette table à partir de RMAN, en s’arrêtant à la séquence 330 qui ne contient donc pas l'opération de delete ci dessus ..

Ici, pas besoin de faire un close de la pluggable database, la restauration n'étant pas complète et étant directement sur un objet précis. Par contre, il faut spécifier sur quelle PDB les tables concernées sont stockées :

Note :
J'ai volontairement fait un DELETE et non pas un DROP TABLE, car dans le cas d'un drop table, il n'est pas nécessaire de passer par une table temporaire via la génération d'un dump, comme je le fais ci dessous.

En effet, RMAN ne permet pas de restaurer le contenu de la table sur elle même, il faut passer par une table temporaire sinon cela plante.

Bien sur vous me direz que si toutes les lignes ont été supprimées, on peut dropper la table et la restaurer entièrement... oui pourquoi pas ! Mais imaginons que seules quelques lignes soient impactées, nous pourrions faire du rattrapage à partir d'une table temporaire, et éviter ainsi d'avoir à restaurer l'intégralité de notre table.

RMAN> recover table MYPDB1.MRS_EXECUTED_BLOCKS of pluggable database MYPDB1
until sequence 374
auxiliary destination '/oratmp' ;

Starting recover at 18-SEP-15
using target database control file instead of recovery catalog
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03002: failure of recover command at 09/18/2015 11:20:05
RMAN-05063: Cannot recover specified tables
RMAN-05112: table "MYPDB1"."MRS_EXECUTED_BLOCKS" already exists

 

-> Donc on lance :

RMAN> recover table MYPDB1.MRS_EXECUTED_BLOCKS of pluggable database MYPDB1
until sequence 374
auxiliary destination '/oratmp'
remap table MYPDB1.MRS_EXECUTED_BLOCKS:MRS_EXECUTED_BLOCKS_TMP;

Starting recover at 18-SEP-15
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=36 device type=DISK
RMAN-05026: WARNING: presuming following set of tablespaces applies to specified Point-in-Time

List of tablespaces expected to have UNDO segments
Tablespace SYSTEM
Tablespace UNDOTBS1

Creating automatic instance, with SID='zhkk'
...
...
...
Finished recover at 18-SEP-15

database opened

contents of Memory Script:
{
sql clone 'alter pluggable database MYPDB1 open';
}
executing Memory Script

sql statement: alter pluggable database MYPDB1 open

Un petit Focus sur la partie "datapump" de RMAN :

contents of Memory Script:

{
# create directory for datapump import
sql 'MYPDB1' "create or replace directory
TSPITR_DIROBJ_DPDIR as ''
/oratmp''";
# create directory for datapump export
sql clone 'MYPDB1' "create or replace directory
TSPITR_DIROBJ_DPDIR as ''
/oratmp''";
}
executing Memory Script

sql statement: create or replace directory TSPITR_DIROBJ_DPDIR as ''/oratmp''

sql statement: create or replace directory TSPITR_DIROBJ_DPDIR as ''/oratmp''

Performing export of tables...
EXPDP> Starting "SYS"."TSPITR_EXP_zhkk_Avay":
EXPDP> Estimate in progress using BLOCKS method...
EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
EXPDP> Total estimation using BLOCKS method: 12 MB
EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
EXPDP> Processing object type TABLE_EXPORT/TABLE/COMMENT
EXPDP> Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
EXPDP> . . exported "MYPDB1"."MRS_EXECUTED_BLOCKS" 9.598 MB 438313 rows
EXPDP> Master table "SYS"."TSPITR_EXP_zhkk_Avay" successfully loaded/unloaded
EXPDP> ******************************************************************************
EXPDP> Dump file set for SYS.TSPITR_EXP_zhkk_Avay is:
EXPDP> /oratmp/tspitr_zhkk_58836.dmp
EXPDP> Job "SYS"."TSPITR_EXP_zhkk_Avay" successfully completed at Fri Sep 18 11:12:21 2015 elapsed 0 00:00:11
Export completed

-> Import avec le remap table :

contents of Memory Script:
{
# shutdown clone before import
shutdown clone abort
}
executing Memory Script

Oracle instance shut down

Performing import of tables...
IMPDP> Master table "SYS"."TSPITR_IMP_zhkk_wCBw" successfully loaded/unloaded
IMPDP> Starting "SYS"."TSPITR_IMP_zhkk_wCBw":
IMPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
IMPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
IMPDP> . . imported "MYPDB1"."MRS_EXECUTED_BLOCKS_TMP" 9.598 MB 438313 rows
IMPDP> Processing object type TABLE_EXPORT/TABLE/COMMENT
IMPDP> Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
IMPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
IMPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
IMPDP> Job "SYS"."TSPITR_IMP_zhkk_wCBw" successfully completed at Fri Sep 18 11:12:24 2015 elapsed 0 00:00:01

-> Et maintenant, RMAN supprime son espace de travail :

Removing automatic instance

Automatic instance removed
auxiliary instance file /oratmp/CDB/datafile/o1_mf_temp_bzqo9tv9_.tmp deleted
auxiliary instance file /oratmp/CDB/datafile/o1_mf_temp_bzqo9th7_.tmp deleted
auxiliary instance file /oratmp/ZHKK_PITR_MYPDB1_CDB/onlinelog/o1_mf_3_bzqoc7g4_.log deleted
auxiliary instance file /oratmp/ZHKK_PITR_MYPDB1_CDB/onlinelog/o1_mf_2_bzqoc7dz_.log deleted
auxiliary instance file /oratmp/ZHKK_PITR_MYPDB1_CDB/onlinelog/o1_mf_1_bzqoc7cq_.log deleted
auxiliary instance file /oratmp/ZHKK_PITR_MYPDB1_CDB/datafile/o1_mf_aedifica_bzqoc5kb_.dbf deleted
auxiliary instance file /oratmp/CDB/datafile/o1_mf_sysaux_bzqo9p7d_.dbf deleted
auxiliary instance file /oratmp/CDB/datafile/o1_mf_system_bzqo9p7f_.dbf deleted
auxiliary instance file /oratmp/CDB/datafile/o1_mf_sysaux_bzqo975w_.dbf deleted
auxiliary instance file /oratmp/CDB/datafile/o1_mf_undotbs1_bzqo975t_.dbf deleted
auxiliary instance file /oratmp/CDB/datafile/o1_mf_system_bzqo975w_.dbf deleted
auxiliary instance file /oratmp/CDB/controlfile/o1_mf_bzqo91sv_.ctl deleted
Finished recover at 18-SEP-15

On vérifie :

SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
0

SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS_TMP";
COUNT(*)
----------
5296

SQL> insert into "MYPDB1"."MRS_EXECUTED_BLOCKS" select * from "MYPDB1"."MRS_EXECUTED_BLOCKS_TMP" ;
5296 rows created.

SQL> commit ;

Commit complete.
SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
5296

SQL> drop table "MYPDB1"."MRS_EXECUTED_BLOCKS_TMP";
Table dropped.

Comme je le mentionnais plus haut, dans le cas d'un drop direct d'une table, l'instruction de recover est plus simple :

SQL> alter session set container=MYPDB1;
Session altered.

SQL> drop table "MYPDB1"."MRS_EXECUTED_BLOCKS";
Table dropped.

La restauration complète de la table :

RMAN> recover table MYPDB1.MRS_EXECUTED_BLOCKS of pluggable database MYPDB1
until sequence 374
auxiliary destination '/oratmp' ;

Et voila, nous avons retrouvé notre table complète :

SQL> select count(*) from "MYPDB1"."MRS_EXECUTED_BLOCKS";
COUNT(*)
----------
5296

Il va de soi qu'il y a plein d'autres tests à faire avec notre ami RMAN, mais cela donne déja une bonne idée de ce que la version 12c permet de faire !

Micka

Partager cet article
Repost0
Pour être informé des derniers articles, inscrivez vous :
Commenter cet article