Cloner vos schémas Oracle avec la commande RMAN Transport Tablespace

A l’heure où les opérations sur vos bases de données doivent être simples, rapides et fiables, faire correspondre schéma(s) applicatif(s) et un jeu de tablespaces est un excellent moyen de gérer clone et migration, y compris d’une plateforme à l’autre.

Evidemment, cela suppose que votre application puisse utiliser comme paramètre le nom de son ou ses schémas. Cela suppose que le jeu de caractère soit suffisamment standard comme AL32UTF8. Cela suppose également que l’application ne s’appuie pas sur des objets partagés comme, par exemple, des privilèges, des synonymes ou des liens de bases de données avec des accès publics. Cela dit, même lorsque ces contraintes ne sont pas vérifiées, l’utilisation des tablespaces transportables peut s’avèrer d’une très grande utilité.

Cet article illustre comment cloner l’ensemble des tables et index du schéma DEMO dans la même base de données dans le schéma DEMO2. Il s’appuie pour cela sur le fait qu’il existe une correspondance entre l’utilisateur DEMO et un jeu de tablespace, en l’occurrence, ici, un seul tablespace. Il s’appuie sur la commande Tranport Tablespace de Recovery Manager. Le graphique ci-dessous illustre l’opération réalisée :

Remarques :

  • Le mécanisme des tablespace transportable copie uniquement les « données » ; Pour copier l’intégralité d’un schéma, vous devrez au préalable importer l’ensemble des objets qui ne sont pas des données et notamment, l’utilisateur, le code applicatif, les tables temporaires, etc
  • L’ensemble des informations nécessaire à la mise en oeuvre de RMAN TRANSPORT TABLESPACE est disponible dans :
    Oracle® Database Backup and Recovery User’s Guide
    Creating Transportable Tablespace Sets
    et

    Oracle® Database Backup and Recovery Reference
    TRANSPORT TABLESPACE

Tablespace et schéma exemple

Pour commencer, nous allons créer un tablespace DEMO_TBS et un utilisateur DEMO pour illustrer le propos. Voici le script associé :

create tablespace demo_tbs 
datafile size 256M;

create user demo
identified by demo
default tablespace demo_tbs;

grant connect, resource to demo;

create table demo.x(id number primary key,
text varchar2(10));

insert into demo.x values (1,'one');
commit;
exit

Sauvegarde de la base de données

Le mécanisme de tablespace transportable lorsqu’il est utilisé avec RMAN s’appuie sur les sauvegardes existantes à travers une instance auxiliaire. Le script ci-dessous effectue une sauvegarde sur disque de la base de données :

mkdir -p /u01/app/oracle/backup
rman target /
show all;
configure channel device type disk format '/u01/app/oracle/backup/%U';
configure controlfile autobackup format for device type disk to '/u01/app/oracle/backup/%U';
backup database plus archivelog delete all input;

Transport du tablespace

Vous voilà prêt à réaliser l' »export » du tablespace ; la commande nécessite de définir un répertoire pour la base de données auxiliaire et un répetoire pour les fichier export datapump et du tablespace ; voici un exemple de script :

host 'mkdir /u01/app/oracle/auxiliary';
host 'mkdir /u01/app/oracle/tt';

transport tablespace demo_tbs
auxiliary destination '/u01/app/oracle/auxiliary'
tablespace destination '/u01/app/oracle/tt';

Note :
Un des intérêts de cette méthode est que vous pouvez par ailleurs choisir le moment de votre export à l’aide de la clause UNTIL TIME.

Voici un exemple de journal de l’opération :

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 UNDO2

Creating automatic instance, with SID='dupx'

initialization parameters used for automatic instance:
db_name=WHITE
db_unique_name=dupx_tspitr_WHITE
compatible=11.2.0.0.0
db_block_size=8192
db_files=200
sga_target=280M
processes=50
db_create_file_dest=/u01/app/oracle/auxiliary
log_archive_dest_1='location=/u01/app/oracle/auxiliary'
#No auxiliary parameter file used


starting up automatic instance WHITE

Oracle instance started

Total System Global Area     292933632 bytes

Fixed Size                     1344512 bytes
Variable Size                100666368 bytes
Database Buffers             184549376 bytes
Redo Buffers                   6373376 bytes
Automatic instance created
Running TRANSPORT_SET_CHECK on recovery set tablespaces
TRANSPORT_SET_CHECK completed successfully

contents of Memory Script:
{
# set requested point in time
set until  scn 4403433;
# restore the controlfile
restore clone controlfile;
# mount the controlfile
sql clone 'alter database mount clone database';
# archive current online log
sql 'alter system archive log current';
}
executing Memory Script

executing command: SET until clause

Starting restore at 24-DEC-11
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=80 device type=DISK

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: restoring control file
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/backup/07muvj72_1_1
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/backup/07muvj72_1_1 tag=TAG20111224T003538
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:01
output file name=/u01/app/oracle/auxiliary/WHITE/controlfile/o1_mf_7hb49rxs_.ctl
Finished restore at 24-DEC-11

sql statement: alter database mount clone database

sql statement: alter system archive log current

contents of Memory Script:
{
# set requested point in time
set until  scn 4403433;
# set destinations for recovery set and auxiliary set datafiles
set newname for clone datafile  1 to new;
set newname for clone datafile  7 to new;
set newname for clone datafile  2 to new;
set newname for clone tempfile  1 to new;
set newname for datafile  3 to
 "/u01/app/oracle/tt/o1_mf_demo_tbs_%u_.dbf";
# switch all tempfiles
switch clone tempfile all;
# restore the tablespaces in the recovery set and the auxiliary set
restore clone datafile  1, 7, 2, 3;
switch clone datafile all;
}
executing Memory Script

executing command: SET until clause

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME< br />
executing command: SET NEWNAME

renamed tempfile 1 to /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_temp_%u_.tmp in control file

Starting restore at 24-DEC-11
using channel ORA_AUX_DISK_1

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_AUX_DISK_1: restoring datafile 00001 to /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_system_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00007 to /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_undo2_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00002 to /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_sysaux_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00003 to /u01/app/oracle/tt/o1_mf_demo_tbs_%u_.dbf
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/backup/06muvj2q_1_1
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/backup/06muvj2q_1_1 tag=TAG20111224T003538
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:01:16
Finished restore at 24-DEC-11

datafile 1 switched to datafile copy
input datafile copy RECID=6 STAMP=770690458 file name=/u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_system_7hb49z2v_.dbf
datafile 7 switched to datafile copy
input datafile copy RECID=7 STAMP=770690458 file name=/u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_undo2_7hb49z51_.dbf
datafile 2 switched to datafile copy
input datafile copy RECID=8 STAMP=770690458 file name=/u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_sysaux_7hb49z36_.dbf
datafile 3 switched to datafile copy
input datafile copy RECID=9 STAMP=770690458 file name=/u01/app/oracle/tt/o1_mf_demo_tbs_7hb49z3g_.dbf

contents of Memory Script:
{
# set requested point in time
set until  scn 4403433;
# online the datafiles restored or switched
sql clone "alter database datafile  1 online";
sql clone "alter database datafile  7 online";
sql clone "alter database datafile  2 online";
sql clone "alter database datafile  3 online";
# recover and open resetlogs
recover clone database tablespace  "DEMO_TBS", "SYSTEM", "UNDO2", "SYSAUX" delete archivelog;
alter clone database open resetlogs;
}
executing Memory Script

executing command: SET until clause

sql statement: alter database datafile  1 online

sql statement: alter database datafile  7 online

sql statement: alter database datafile  2 online

sql statement: alter database datafile  3 online

Starting recover at 24-DEC-11
using channel ORA_AUX_DISK_1

starting media recovery

channel ORA_AUX_DISK_1: starting archived log restore to default destination
channel ORA_AUX_DISK_1: restoring archived log
archived log thread=1 sequence=191
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/backup/08muvj75_1_1
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/backup/08muvj75_1_1 tag=TAG20111224T003757
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:01
archived log file name=/u01/app/oracle/auxiliary/1_191_764756240.dbf thread=1 sequence=191
channel clone_default: deleting archived log(s)
archived log file name=/u01/app/oracle/auxiliary/1_191_764756240.dbf RECID=5 STAMP=770690461
media recovery complete, elapsed time: 00:00:01
Finished recover at 24-DEC-11

database opened

contents of Memory Script:
{
# make read only the tablespace that will be exported
sql clone 'alter tablespace  DEMO_TBS read only';
# create directory for datapump export
sql clone "create or replace directory STREAMS_DIROBJ_DPDIR as ''
/u01/app/oracle/tt''";
}
executing Memory Script

sql statement: alter tablespace  DEMO_TBS read only

sql statement: create or replace directory STREAMS_DIROBJ_DPDIR as ''/u01/app/oracle/tt''

Performing export of metadata...
   EXPDP> Starting "SYS"."TSPITR_EXP_dupx": 
   EXPDP> Processing object type TRANSPORTABLE_EXPORT/PLUGTS_BLK
   EXPDP> Processing object type TRANSPORTABLE_EXPORT/TABLE
   EXPDP> Processing object type TRANSPORTABLE_EXPORT/CONSTRAINT/CONSTRAINT
   EXPDP> Processing object type TRANSPORTABLE_EXPORT/POST_INSTANCE/PLUGTS_BLK
   EXPDP> Master table "SYS"."TSPITR_EXP_dupx" successfully loaded/unloaded
   EXPDP> ******************************************************************************
   EXPDP> Dump file set for SYS.TSPITR_EXP_dupx is:
   EXPDP>   /u01/app/oracle/tt/dmpfile.dmp
   EXPDP> ******************************************************************************
   EXPDP> Datafiles required for transportable tablespace DEMO_TBS:
   EXPDP>   /u01/app/oracle/tt/o1_mf_demo_tbs_7hb49z3g_.dbf
   EXPDP> Job "SYS"."TSPITR_EXP_dupx" successfully completed at 00:42:51
Export completed

/*
   The following command may be used to import the tablespaces.
   Substitute values for >logon> and >directory>.
   impdp> directory=>directory> dumpfile= 'dmpfile.dmp' transport_datafiles= /u01/app/oracle/tt/o1_mf_demo_tbs_7hb49z3g_.dbf
*/
[...]
--------------------------------------------------------------
-- End of sample PL/SQL script
--------------------------------------------------------------

Removing automatic instance
shutting down automatic instance
database closed
database dismounted
Oracle instance shut down
Automatic instance removed
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_temp_7hb4dn3q_.tmp deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/onlinelog/o1_mf_3_7hb4dld9_.log deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/onlinelog/o1_mf_2_7hb4djlo_.log deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/onlinelog/o1_mf_1_7hb4dgot_.log deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_sysaux_7hb49z36_.dbf deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_undo2_7hb49z51_.dbf deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/datafile/o1_mf_system_7hb49z2v_.dbf deleted
auxiliary instance file /u01/app/oracle/auxiliary/WHITE/controlfile/o1_mf_7hb49rxs_.ctl deleted

Importer et renommer le tablespace

Importer le tablespace nécessite de mettre à disposition le fichier et de créer  l’utilisateur destinataire des tables et index. En outre, vous devrez créer un directory pour que datapump puisse accéder au fichier d’import et exporter/importer tous les objets en plus des tables et index. Voici un exemple de script qui effectue les opérations de prépation :

mv /u01/app/oracle/tt/o1_mf_demo_tbs_7hb49z3g_.dbf 
/u01/app/oracle/oradata/WHITE/demo2_tbs.dbf;
create directory dpump_dir as '/u01/app/oracle/tt';
create user demo2 identified by demo2;

Vous voilà prêt à exécuter l’import :

impdp "/ as sysdba" directory=dpump_dir dumpfile=dmpfile.dmp 
transport_datafiles=/u01/app/oracle/oradata/WHITE/demo2_tbs2.dbf
remap_schema=demo:demo2 remap_tablespace=demo_tbs:demo2_tbs

Et voici un exemple de journal correspondant :

Import: Release 11.2.0.3.0 - Production on Sat Dec 24 08:38:37 2011

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Producti on
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Master table "SYS"."SYS_IMPORT_TRANSPORTABLE_01" successfully loaded/unloaded
Starting "SYS"."SYS_IMPORT_TRANSPORTABLE_01":  "/******** AS SYSDBA" directory=dpump_dir dumpfile=dmpfile.dmp transport_datafiles=/u01/app/oracle/oradata/WHITE/demo2_tbs.dbf remap_schema=demo:demo2 remap_tablespace=demo_tbs:demo2_tbs
Processing object type TRANSPORTABLE_EXPORT/PLUGTS_BLK
Processing object type TRANSPORTABLE_EXPORT/TABLE
Processing object type TRANSPORTABLE_EXPORT/CONSTRAINT/CONSTRAINT
Processing object type TRANSPORTABLE_EXPORT/POST_INSTANCE/PLUGTS_BLK
Job "SYS"."SYS_IMPORT_TRANSPORTABLE_01" successfully completed at 08:38:39

Mettre le tablespace en READ WRITE

Pour terminer vous devrez passer le tablespace en mode lecture/écriture et changer les propriétés de l’utilisateur ; le nouveau schéma est opérationnel :

alter tablespace demo2_tbs read write;
alter user demo2 default tablespace demo2;
select * from demo2.x;

ID TEXT
----- ----------
1 one


insert into demo2.x values (2,'two');
commit;

Conclusion

Si l’ensemble du processus semble, a priori, plus complexe qu’un export/import, l’objectif de cet article est de montrer qu’il ne s’agit après tout que de moins de 10 lignes faciles à automatiser. Les avantages sont multiples et notamment en terme de performance : pas d’accès au schéma source pour la copie, pas de reconstruction d’index.

En outre la méthode fonctionne pour les migrations vers des versions supérieures ou des bases de données avec des systèmes différents. Mais pourquoi utiliser des exports encore quand on peut utiliser RMAN ?