Habituellement, pour dupliquer des bases de données pour créer différents environnements, j’utilise la commande RMAN Duplicate à partir d’une sauvegarde sur disque.
L’avantage de cette commande Duplicate (qui est en réalité un script Rman) est qu’une fois le fichier de démarrage de l’instance créé avec les règles de renommage des datafiles correctement définies, celui-ci prend en charge toutes les étapes : restauration des controlfiles, restauration et renommage de datafiless, recréation des redologs , recover , renommage de la base et open resetlogs.
Récemment, en voulant dupliquer une base de données en version 12.1.0.2 par cette méthode, je suis tombé sur un bug qui fait planter le duplicate dès le début lorsque le script essaie de cataloguer le contenu du répertoire contenant la sauvegarde pointé par la directive BACKUP_LOCATION :
ORA-07445: exception encountered: core dump [ksfd_io()+10625] [SIGFPE] [ADDR:0xC4F60D1] [PC:0xC4F60D1] [Integer divide by zero] [] ORA-27048: skgfifi: file header information is invalid
Après quelques recherches, il semble qu’il s’agisse d’un bug affectant la version 12.1.0.2 (quelle chance !) :
Bug 22223463 – RMAN catalog process reports ORA-3113 and ORA-7445 [ksfd_io] (Doc ID 22223463.8)
Le problème proviendrait de la présence de fichiers non générés par RMAN dans le répertoire de sauvegarde comme une fichier de log par exemple. Le contournement consistant à supprimer ces fichiers n’a pas fonctionné, je ne sais pourquoi…
Ayant besoin de réaliser cette opération rapidement et n’ayant pas la possibilité d’appliquer rapidement le patch proposé, j’ai dû me résoudre à utiliser une autre méthode en passant par une commande ne cataloguant pas le contenu du répertoire de sauvergarde, c’est à dire un classique RESTORE DATABASE.
Ceci étant, je pense qu’un DUPLICATE avec connexion à la target aurait aussi fait l’affaire, mais il était plus long à mettre en œuvre dans mon environnement (mots de passe sys à connaitre, fichier orapw à mettre à jour, …)
Cela peut sembler très simple à première vue de vouloir dupliquer une base par la commande restore database, mais étant sur le même serveur que la base dont j’utilisais le backup, il me fallait pouvoir changer le nom de la base, les chemins des datafiles et tempfiles et surtout ne pas écraser les fichiers de la base d’origine en particulier les redologs. Après quelques tâtonnements et de multiples erreurs, j’ai pu trouver le mode opératoire idéal.
Restauration de la base
1/ Créer un fichier init.ora minimal de démarrage de la nouvelle base (MADB2) que l’on va restaurer à partir du backup de la base (MADB1).
Important : Dans celui-ci, le DBNAME doit rester celui de la base initiale (MADB1) pour que cette information reste cohérente entre les controlfiles et les datafiles le temps de la restauration et du recover.
Par contre, les autres paramètres dont le DB_UNIQUE_NAME et les controlfiles doivent référencer la nouvelle base !
# cat initMADB2.ora DB_NAME=MADB1 # Nom de la base dont on utilise le backup compatible='12.1.0' DB_UNIQUE_NAME=MADB2 audit_file_dest='/home/oracle/admin/MADB2/adump' control_files='+DATA1/MADB2/control01.ctl','+DATA1/MADB2/control02.ctl' cluster_database='FALSE' log_archive_format='MADB2_%r_%s_%t.arc' DB_BLOCK_SIZE=8192 diagnostic_dest='/logiciels/oracle' audit_trail='NONE' DB_CREATE_FILE_DEST='+DATA1' DB_RECOVERY_FILE_DEST='+FRA1' DB_RECOVERY_FILE_DEST_SIZE=500G log_archive_dest_1='LOCATION=USE_DB_RECOVERY_FILE_DEST valid_for=(all_logfiles,all_roles) undo_tablespace=UNDO1
Démarrer une instance de la base MADB2 en nomount à partir de ce fichier d’init.
Il s’agit ici d’une base RAC OneNode d’où le suffixe « _1 » au nom de l’instance, cela fonctionnerait de la même façon avec une base RAC ou Standalone.
export ORACLE_SID=MADB2_1 sqlplus / as sysdba startup nomount pfile='/home/oracle/MADB2/initMADB2.ora';
2/ Restaurer les controlfiles à partir du backup RMAN
rman target / RMAN> restore controlfile from '/backup/MADB1/ctrlfile_backup.ctl'; channel ORA_DISK_1: copied control file copy output file name=+DATA1/MADB2/control01.ctl output file name=+FRA1/MADB2/control02.ctl
Les controlfiles sont restaurés dans le répertoire ASM de la nouvelle base grâce au DB_UNIQUE_NAME qui est renseigné à MADB2 dans le fichier init.ora utilisé pour la restauration !
On peut maintenant passer la base en MOUNT pour lancer la restauration.
RMAN> alter database mount;
3/ Restaurer les datafiles, tempfiles
Pour cela il faut passer par un block de commandes RMAN : run {}
Le nouvel emplacement des datafiles pendant la restauration sera indiqué par la directive set newname for database.
Pour simplifier, j’ai laissé Oracle définir les noms des datafiles (OMF), j’ai simplement choisi l’option %b.
set newname for database to « +DATA1/MADB2/datafile/%b »;
D’autres options sont possibles dont celle de nommer explicitement chaque datafiile (alias) avec des ordres set newname for datafile x pour chacun des datafiles de la base.
Pour les tempfiles, il faut juste en connaitre le nombre et utiliser la directive NEW qui laisse Oracle définir leurs noms mais il faut pour cela que le paramètre DB_CREATE_FILE_DEST soit renseigné dans le fichier init.ora utilisé pour démarrer l’instance.
Pour les 2 tempfiles de la base d’origine, cela donne :
set newname for tempfile 1 to NEW;
set newname for tempfile 2 to NEW;
4/ Renommage des redologs
Pour les redologs, le plus sûr est de les renommer directement dans le controlfile dans le même block run {} avant l’ordre restore database, ainsi on sera certain de ne pas écraser les reldologs de la base d’origine (!).
Ceux-ci seront recréés au moment de l’ouverture de la base en mode resetlogs. C’est un peu fastidieux la 1ère fois (mais réutilisable) puisqu’il faut récupérer les noms des fichiers membres des redologs sur la base d’origine (select member from v$logfile) et écrire les ordres de renommage de la manière suivante :
sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_1.554.1049913517'' to ''+DATA1/MADB2/redo01_1.rdo''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_1.695.1049913517'' to ''+FRA1/MADB2/redo01_2.rdo''"; ...etc... pour tous les meredologs...membres des groupes de redologs
Les fichiers de groupes de redologs seront récréés dans les nouveaux emplacements, ici sous forme d’alias dans : +DATA1/MADB2 et +FRA1/MADB2.
A noter cependant qu’en entrée il faut nommer explicitement les membres des groupes de redologs, par contre en sortie on peut utiliser un alias comme ici ou bien juste le nom du diskgroup ASM (ou du répertoire) pour laisser Oracle générer un nom OMF sans alias.
Le block RUN doit comporter après la restauration les switchs vers les nouveaux noms des datafiles et tempfiles dans les controlfiles. Ces switchs doivent être faits dans le même block que le restore :
restore database; switch datafile all; switch tempfile all;
Le block run {} RMAN au complet est donc le suivant pour 1 restore sur 4 channels :
run { allocate channel c1 type disk; allocate channel c2 type disk; allocate channel c3 type disk; allocate channel c4 type disk; set newname for database to "+DATA1/MADB2/datafile/%b"; set newname for tempfile 1 to NEW; set newname for tempfile 2 to NEW; sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_1.554.1049913517'' to ''+DATA1''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_1.695.1049913517'' to ''+FRA1''"; sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_2.555.1049913523'' to ''+DATA1''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_2.702.1049913523'' to ''+FRA1''"; sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_3.556.1049913525'' to ''+DATA1''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_3.705.1049913525'' to ''+FRA1''"; sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_21.557.1049913529'' to ''+DATA1''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_21.706.1049913529'' to ''+FRA1''"; sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_22.558.1049913529'' to ''+DATA1''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_22.707.1049913531'' to ''+FRA1''"; sql "alter database rename file ''+DATA1/MADB1/onlinelog/group_23.559.1049913531'' to ''+DATA1''"; sql "alter database rename file ''+FRA1/MADB1/onlinelog/group_23.708.1049913531'' to ''+FRA1''"; restore database; switch datafile all; switch tempfile all; }
Après cela , il ne reste qu’a exécuter un recover database qui peut être NOREDO puisque les redlogs n’existent pas.
Si le recover database est fait dans le block RUN, il ne se passe rien pour une raison que je n’ai pas encore comprise et dans ce cas le open resetlogs échoue (file 1 needs more recovery …).
Donc, en dehors d’un block RUN, exécuter :
RMAN> recover database noredo; RMAN> alter database open resetlogs;
Et voilà, il ne reste plus qu’une chose à faire : modifier le nom de la base dans les controlfiles et les datafiles car celle-ci se nomme toujours MADB1 dans ceux-ci après la restauration.
Pour cela on va utiliser l’utilitaire fourni par Oracle : DB New ID = NID
Changement du nom de la base
Il faut d’abord redémarrer la base en mode MOUNT avant d’exécuter l’utilitaire NID.
Puis on lance nid en indiquant le nouveau DBNAME voulu avec l’option setname=yes (nid peut aussi changer uniquement de DBID de la base).
Répondre Y à la question Change database name of database MADB1 to MADB2 ? (Y/[N])
nid target=/ dbname=MADB2 setname=yes DBNEWID: Release 12.1.0.2.0 - Production on Fri Sep 4 23:15:16 2020 Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved. Connected to database MADB1 (DBID=2074379348) Connected to server version 12.1.0 Control Files in database: +DATA1/MADB2/control01.ctl +FRA1/MADB2/control02.ctl Change database name of database MADB1 to MADB2 ? (Y/[N]) => Y Proceeding with operation Changing database name from MADB1 to MADB2 Control File +DATA1/MADB2/control01.ctl - modified Control File +FRA1/MADB2/control02.ctl - modified Datafile +DATA1/MADB2/DATAFILE/system.661.105026833 - wrote new name Datafile +DATA1/MADB2/DATAFILE/sysaux.653.105026824 - wrote new name ... Datafile +DATA1/MADB2/TEMPFILE/tools.663.105027505 - wrote new name Control File +DATA1/MADB2/control01.ctl - wrote new name Control File +FRA1/MADB2/control02.ctl - wrote new name Instance shut down Database name changed to MADB2. Modify parameter file and generate a new password file before restarting. Succesfully changed database name. DBNEWID - Completed succesfully.
Dernière étape, comme demandé par le script : il faut modifier le paramètre DBNAME dans l’init.ora de la base (MADB1=>MADB2) et créer un nouveau password file (orapwMADB2).
Enfin, pour finaliser la nouvelle base, il reste entre autres à créer un fichier spfile à partir d’un fichier pfile complet et dans le cas d’une base sur cluster, créer la ressource correspondante avec srvctl add database.
Finalement, ce mode opératoire est assez simple et rapide, surtout si on utilise le nommage OMF et que l’on a plusieurs bases à cloner à partir d’un même backup, cela peut donc être une bonne alterrnative au duplicate dans certains cas.