Les présentations des fonctionnalités multitenant de la 12C nous ont fait rêver d’une méthode de migration utlra simple pour passer d’une version de la base à une autre. Procédure que j’imagine en six étapes :
1) installation des nouveaux binaires
2) Création d’un container racine avec la nouvelle version
3) Arrêt de la base pluggable cible
4) Unplug de la base du container de l’ancienne version
5) Plug de la base dans le nouveau container
6) Ouverture de la base
Et c’est fini ! Le temps d’arrêt, entre l’étape 3) et l’étape 6), est réduit à la durée du déplacement des fichiers (qui n’est pas obligatoire)
Vu que le dictionnaire est dans le container racine et que c’est de lui dont dépend la version de la base, pourquoi ne pas y croire.
Voyons qu’elle est la réalité avec un cas d’école.
Environnement :
- Système linux 64bits (Virtual Box) avec OEL6.1
- Version 12.1.0.1 du logiciel base de données opérationnelle
- Container cdbELE en version 12.1.2.0.1 (ORACLE_HOME=/u01/app/oracle/product/12.1.0.1)
- Base PDBELE pluggée sur le container cdbELE , base créée depuis le template et alimenté par un schéma SOE , schéma Order Entry de l’application de test Swingbench
- Distribution database 12.1.2.0.2 installée (ORACLE_HOME=/u01/app/oracle/product/12.1.0.2)
- Container cdb1212 créé vide.
Les étapes 1 et 2 sont donc déjà réalisée , déroulons la suite de la méthode:
Etape 3) Arrêt de la base pluggable cible
J’ajoute, par précaution avant de « déplugger » la base, le passage du script de vérification préalable à la mise à jour:
– Connexion sur le container source en version 12.1.0.1 : cdbELE
[oracle@ele1ole6 ~]$ . oraenv ORACLE_SID = [oracle] ? cdbELE The Oracle base remains unchanged with value /u01/app/oracle [oracle@ele1ole6 ~]$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.1.0 Production on Thu Aug 14 09:28:30 2014 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to: Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 PDBELE READ WRITE NO SQL> alter session set container=pdbELE ; SQL> @/u01/app/oracle/product/12.1.0.2/rdbms/admin/preupgrd.sql
Résultat contenu dans le fichier journal: tous les composants sont valides, pas d’erreur , pas de point d’attention, un seul message informatif apparait concernant la version d’APEX actuellement dans la base :
…/… ****************************************************************** [Pre-Upgrade Checks] ********************************************************************** INFORMATION: --> Oracle Application Express (APEX) can be manually upgraded prior to database upgrade APEX is currently at version 4.2.0.00.27 and will need to be upgraded to APEX version 4.2.5 in the new release. Note 1: To reduce database upgrade time, APEX can be manually upgraded outside of and prior to database upgrade. Note 2: See MOS Note 1088970.1 for information on APEX installation upgrades. …/…
Je me sens donc prêt et serein pour mon opération.
– Arrêt du pdb cible PDBELE connecté sur le container d’origine :
SQL> alter session set container=CDB$ROOT ; SQL> alter pluggable database pdbELE close ; SQL> show pdbs 2 PDB$SEED READ ONLY NO 3 PDBELE MOUNTED
Etape 4) Unplug de mon PDB depuis le container d’origine
Une seule commande à passer, opération très rapide qui génère une description de la base dans le fichier xml donné :
SQL> alter pluggable database pdbELE unplug into '/home/oracle/pdbELE.xml' ;
A noter qu’a partir de ce moment, une fois la base “dépluggée” , la seule opération qui peut être réalisée dans le container d’origine pour cette base est une suppression via la clause « DROP », il sera impossible de la rouvrir dans le même container sans faire une opération de “plugging” avec les bonnes options.
Etape 5) Plug de la base PDBELE dans le nouveau container CDB1212
Avant cela, il existe déjà un moyen de contrôle de la compatibilité pour la base que l’on veut traiter via le package DBMS_PDB.CHECK_PLUG_COMPATIBILTY, on peut l’utiliser de cette manière :
Connexion sur le container racine cible CDB1212
[oracle@ele1ole6 ~]$ . oraenv ORACLE_SID = [oracle] ? cdb1212 The Oracle base remains unchanged with value /u01/app/oracle [oracle@ele1ole6 ~]$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.2.0 Production on Thu Aug 14 09:40:30 2014 Copyright (c) 1982, 2013, 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 serveroutput on SQL> DECLARE compatible CONSTANT VARCHAR2(3) := CASE DBMS_PDB.CHECK_PLUG_COMPATIBILITY( pdb_descr_file => '/home/oracle/pdbELE.xml' , pdb_name => 'PDBELE' ) WHEN TRUE THEN 'YES' ELSE 'NO' END; BEGIN DBMS_OUTPUT.PUT_LINE(compatible); END; /
Première déconvenue, le résultat est : NO , la vue PDB_PLUG_IN_VIOLATIONS nous donne plus d’informations :
SQL> select message, status from pdb_plug_in_violations where type like '%ERR%'; MESSAGE STATUS --------------------------------------------------------------------------------------------------------- PDB's version does not match CDB's version: PDB's version 12.1.0.0.0. CDB's version 12.1.0.2.0. PENDING APEX mismatch: PDB installed version 4.2.0.00.27 CDB installed version 4.2.5.00.08 PENDING
Le message concernant APEX ne me perturbe pas, l’opération de suppression et de réinstallation du module est possible et bien documenté via la note MOS 558340.1, par contre l’incohérence de version entre le PDB et le CDB, m’interroge sur la faisabilité de ma migration miracle ! Allons au bout de notre idée :
– Plugging de la base , par création d’une nouvelle base pluggable:
J’utilise l’option “using <xml file>” et la conversion de la localisation des fichiers via la clause “file_name_convert” , par défaut les fichiers sont copiés et non pas déplacés:
SQL> create pluggable database pdbELE using '/home/oracle/pdbELE.xml' file_name_convert=('/u01/oradata/cdbELE/pdbELE','/u03/oradata/cdb1212/pdbELE') ;
Résultat : “Pluggable database created.“
Il me reste un faible espoir d’aboutir, l’instant de vérité est proche.
Etape 6) Ouverture de la base en lecture/écriture
SQL> alter pluggable database PDBELE open ; Warning: PDB altered with errors.
Aie ! ce n’est pas ce que j’espérais !
En fait la base est ouverte , mais dans le mode special “MIGRATE” et “RESTRICTED” :
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 PDBELE MIGRATE YES
Cest l’équivalent de la commande :
SQL> alter pluggable database pdbele open upgrade ;
On retrouve bien ces informations dans les traces du fichier d’alerte :
ORA-65000 signalled during: alter pluggable database open ... 2014-08-14 10:30:58.166000 +02:00 alter pluggable database PDBELE open Pluggable database PDBELE dictionary check beginning Pluggable Database PDBELE Dictionary check complete Database Characterset for PDBELE is WE8MSWIN1252 *************************************************************** WARNING: Pluggable Database PDBELE with pdb id - 3 is altered with errors or warnings. Please look into PDB_PLUG_IN_VIOLATIONS view for more details. *************************************************************** Due to limited space in shared pool (need 6094848 bytes, have 3981120 bytes), limiting Resource Manager entities from 2048 to 32 2014-08-14 10:30:59.665000 +02:00 Opening pdb PDBELE (3) with Resource Manager plan: DEFAULT_PLAN ALTER SYSTEM SET _system_trig_enabled=FALSE SCOPE=MEMORY; ALTER SYSTEM SET enable_ddl_logging=FALSE SCOPE=MEMORY; Resource Manager disabled during database migration: plan '' not set ALTER SYSTEM SET resource_manager_plan= SCOPE=MEMORY; ALTER SYSTEM SET recyclebin='OFF' DEFERRED SCOPE=MEMORY; Pluggable database PDBELE opened read write Completed: alter pluggable database PDBELE open
C’est confirmer par contenu de la vue PDB_PLUG_IN_VIOLATIONS qui insiste sur le fait que les deux versions du dictionnaire ne sont pas compatibles:
SQL> select message, status from pdb_plug_in_violations where type like '%ERR%'; MESSAGE STATUS --------------------------------------------------------------------------------------------------------- PDB's version does not match CDB's version: PDB's version 12.1.0.1.0. CDB's version 12.1.0.2.0. PENDING
Cela ne suffit donc pas, adieu nos rêves de méthode de migration miracle, les liens entre le dictionnaire de la base pluggable (qui contient ses propres objets) et ceux des objets communs fournis par Oracle dans le dictionnaire racine doivent être refait. l’hypothèse de départ est fausse car il y a bien deux dictionnaires différent reliés par des pointeurs!
Pour s’en sortir pas d’autre solution que de passer par l’étape de mise à jour , soit:
Etape 6) qui devient : Mise à niveau du dictionnaire de la PDB
Le script à utiliser est le perl catctl.pl de la version, le même que pour une base en architecture traditionnelle et que j’ai déja testé ici. Il se trouve sous $ORACLE_HOME/rdbms/admin de la version cible, et nécessite un répertoire de destination si on veut lui faire générer des fichiers journaux. Je l’utilise ainsi avec le nom du container concerné passé à l’argument « -c » :
[oracle@ele1ole6 ~]$ cd $ORACLE_HOME/rdbms/admin [oracle@ele1ole6 admin]$ mkdir /home/oracle/upgradePDBELE [oracle@ele1ole6 admin]$ /u01/app/oracle/product/12.1.0.2/perl/bin/perl catctl.pl -c "PDBELE" -l /home/oracle/upgradePDBELE catupgrd.sql
Voici la sortie générée :
Argument list for [catctl.pl] SQL Process Count n = 0 SQL PDB Process Count N = 0 Input Directory d = 0 Phase Logging Table t = 0 Log Dir l = /home/oracle/upgradePDBELE Script s = 0 Serial Run S = 0 Upgrade Mode active M = 0 Start Phase p = 0 End Phase P = 0 Log Id i = 0 Run in c = PDBELE Do not run in C = 0 Echo OFF e = 1 No Post Upgrade x = 0 Reverse Order r = 0 Open Mode Normal o = 0 Debug catcon.pm z = 0 Debug catctl.pl Z = 0 Display Phases y = 0 Child Process I = 0 catctl.pl version: 12.1.0.2.0 Oracle Base = /u01/app/oracle Analyzing file catupgrd.sql Log files in /home/oracle/upgradePDBELE catcon: ALL catcon-related output will be written to /home/oracle/upgradePDBELE/catupgrd_catcon_3693.lst catcon: See /home/oracle/upgradePDBELE/catupgrd*.log files for output generated by scripts catcon: See /home/oracle/upgradePDBELE/catupgrd_*.lst files for spool files, if any Number of Cpus = 1 Parallel PDB Upgrades = 2 SQL PDB Process Count = 2 SQL Process Count = 0 New SQL Process Count = 1 [CONTAINER NAMES] CDB$ROOT PDB$SEED PDBELE PDB Inclusion:[PDBELE] Exclusion:[] Starting [/u02/app/oracle/product/12.1.0.2/perl/bin/perl catctl.pl -c 'PDBELE' -l /home/oracle/upgradePDBELE -I -i pdbele -n 2 catupgrd.sql] Argument list for [catctl.pl] SQL Process Count n = 2 SQL PDB Process Count N = 0 Input Directory d = 0 Phase Logging Table t = 0 Log Dir l = /home/oracle/upgradePDBELE Script s = 0 Serial Run S = 0 Upgrade Mode active M = 0 Start Phase p = 0 End Phase P = 0 Log Id i = pdbele Run in c = PDBELE Do not run in C = 0 Echo OFF e = 1 No Post Upgrade x = 0 Reverse Order r = 0 Open Mode Normal o = 0 Debug catcon.pm z = 0 Debug catctl.pl Z = 0 Display Phases y = 0 Child Process I = 1 catctl.pl version: 12.1.0.2.0 Oracle Base = /u01/app/oracle Analyzing file catupgrd.sql Log files in /home/oracle/upgradePDBELE catcon: ALL catcon-related output will be written to /home/oracle/upgradePDBELE/catupgrdpdbele_catcon_3775.lst catcon: See /home/oracle/upgradePDBELE/catupgrdpdbele*.log files for output generated by scripts catcon: See /home/oracle/upgradePDBELE/catupgrdpdbele_*.lst files for spool files, if any Number of Cpus = 1 SQL PDB Process Count = 2 SQL Process Count = 2 [CONTAINER NAMES] CDB$ROOT PDB$SEED PDBELE PDB Inclusion:[PDBELE] Exclusion:[] ------------------------------------------------------ Phases [0-73] Container Lists Inclusion:[PDBELE] Exclusion:[] Serial Phase #: 0 Files: 1 Time: 10s PDBELE Serial Phase #: 1 Files: 5 Time: 39s PDBELE .../... Serial Phase #:62 Files: 1 Time: 126s PDBELE Restart Phase #:63 Files: 1 Time: 0s PDBELE Serial Phase #:64 Files: 1 Time: 0s PDBELE Serial Phase #:65 Files: 1 Calling sqlpatch with LD_LIBRARY_PATH=/u02/app/oracle/product/12.1.0.2/lib; export LD_LIBRARY_PATH;/u02/app/oracle/product/12.1.0.2/perl/bin/perl -I /u02/app/oracle/product/12.1.0.2/rdbms/admin -I /u02/app/oracle/product/12.1.0.2/rdbms/admin/../../sqlpatch /u02/app/oracle/product/12.1.0.2/rdbms/admin/../../sqlpatch/sqlpatch.pl -verbose -upgrade_mode_only -pdbs PDBELE > /home/oracle/upgradePDBELE/catupgrdpdbele_datapatch_upgrade.log 2> /home/oracle/upgradePDBELE/catupgrdpdbele_datapatch_upgrade.err returned from sqlpatch Time: 10s PDBELE Serial Phase #:66 Files: 1 Time: 3s PDBELE Serial Phase #:68 Files: 1 Time: 3s PDBELE Serial Phase #:69 Files: 1 Calling sqlpatch with LD_LIBRARY_PATH=/u02/app/oracle/product/12.1.0.2/lib; export LD_LIBRARY_PATH;/u02/app/oracle/product/12.1.0.2/perl/bin/perl -I /u02/app/oracle/product/12.1.0.2/rdbms/admin -I /u02/app/oracle/product/12.1.0.2/rdbms/admin/../../sqlpatch /u02/app/oracle/product/12.1.0.2/rdbms/admin/../../sqlpatch/sqlpatch.pl -verbose -pdbs PDBELE > /home/oracle/upgradePDBELE/catupgrdpdbele_datapatch_normal.log 2> /home/oracle/upgradePDBELE/catupgrdpdbele_datapatch_normal.err returned from sqlpatch Time: 11s PDBELE Serial Phase #:70 Files: 1 Time: 79s PDBELE Serial Phase #:71 Files: 1 Time: 11s PDBELE Serial Phase #:72 Files: 1 Time: 5s PDBELE Serial Phase #:73 Files: 1 Time: 0s PDBELE Grand Total Time: 1355s PDBELE LOG FILES: (catupgrdpdbele*.log) Upgrade Summary Report Located in: /u01/app/oracle/product/12.1.0.2/cfgtoollogs/cdb1212/upgrade/upg_summary.log Total Upgrade Time: [0d:0h:22m:35s] Time: 1358s For PDB(s) Grand Total Time: 1358s LOG FILES: (catupgrd*.log) Grand Total Upgrade Time: [0d:0h:22m:38s]
Cela prend pratiquement autant de temps que pour une base Oracle traditionnelle , et c’est dommage!
On pouvait penser qu’en manipulant des liens plutôt que des données dans les dictionnaires, le traitement soit plus rapide.
On vérifie qu’il n’y a pas de lignes d’erreur dans les fichiers journaux et on peut passer à la dernière étape : l’ouverture de la base ,
car en fin du perl celle-ci est arrêté, en voici la preuve dans le fichier d’alerte :
2014-08-14 11:40:12.656000 +02:00 SERVER COMPONENT id=POSTUP_END: timestamp=2014-08-14 11:40:12 Container=PDBELE Id=3 2014-08-14 11:40:28.333000 +02:00 ALTER PLUGGABLE DATABASE CLOSE IMMEDIATE 2014-08-14 11:40:31.680000 +02:00 ALTER SYSTEM: Flushing buffer cache inst=0 container=3 local Pluggable database PDBELE closed Completed: ALTER PLUGGABLE DATABASE CLOSE IMMEDIATE
Etape 7) Ouverture de la base et dernière recompilation des objets invalides
SQL> alter pluggable database PDBELE open ; Pluggable database altered.
Nécessité de faire une recompilation des objets via utlrp :
SQL> alter session set container=PDBELE SQL> select count(*) from dba_objects where status not like 'VALID' ; COUNT(*) --------- 728 SQL> @?/rdbms/admin/utlrp TIMESTAMP -------------------------------------------------------------------------------- COMP_TIMESTAMP UTLRP_BGN 2014-08-19 10:24:07 DOC> DOC># PL/SQL procedure successfully completed. TIMESTAMP -------------------------------------------------------------------------------- COMP_TIMESTAMP UTLRP_END 2014-08-19 10:24:11 DOC> The following query reports the number of objects that have compiled .../... DOC> OBJECTS WITH ERRORS ------------------- 0 DOC> The following query reports the number of errors caught during DOC> recompilation. If this number is non-zero, please query the error DOC> messages in the table UTL_RECOMP_ERRORS to see if any of these errors DOC> are due to misconfiguration or resource constraints that must be DOC> fixed before objects can compile successfully. DOC># ERRORS DURING RECOMPILATION --------------------------- 0 Function created. PL/SQL procedure successfully completed. Function dropped. ...Database user "SYS", database schema "APEX_040200", user# "98" 10:24:34 ...Compiled 0 out of 3014 objects considered, 0 failed compilation 10:24:34 ...271 packages ...263 package bodies ...452 tables ...11 functions ...16 procedures ...3 sequences ...457 triggers ...1320 indexes ...211 views ...0 libraries ...6 types ...0 type bodies ...0 operators ...0 index types ...Begin key object existence check 10:24:34 ...Completed key object existence check 10:24:35 ...Setting DBMS Registry 10:24:35 ...Setting DBMS Registry Complete 10:24:35 ...Exiting validate 10:24:35 PL/SQL procedure successfully completed.
Noter que tous les composants sont dans le bon status :
SQL>select comp_name ,version , status from dba_registry ; COMP_NAME VERSION STATUS ------------------------------ ------------------------------ ----------- Oracle Database Vault 12.1.0.2.0 VALID Oracle Application Express 4.2.5.00.08 VALID Oracle Label Security 12.1.0.2.0 VALID Spatial 12.1.0.2.0 VALID Oracle Multimedia 12.1.0.2.0 VALID Oracle Text 12.1.0.2.0 VALID Oracle Workspace Manager 12.1.0.2.0 VALID Oracle XML Database 12.1.0.2.0 VALID Oracle Database Catalog Views 12.1.0.2.0 VALID Oracle Database Packages and T 12.1.0.2.0 VALID JServer JAVA Virtual Machine 12.1.0.2.0 VALID Oracle XDK 12.1.0.2.0 VALID Oracle Database Java Packages 12.1.0.2.0 VALID OLAP Analytic Workspace 12.1.0.2.0 VALID Oracle OLAP API 12.1.0.2.0 VALID Oracle Real Application Cluste 12.1.0.2.0 OPTION OFF
Finalisation
Il reste à mettre en place le listener de la nouvelle version, l’utilisation de « netca » est le plus simple pour cela. Attention si vous positionnez un port d’écoute différent de la valeur standard 1521 à ne pas oublier le paramétrage de « local_listener » pour cdb1212, exemple avec un port d’écoute sur la valeur 1522 :
a) Ajout entrée dans le fichier tnsnames.ora :
LISTENER_CDB1212 = (ADDRESS = (PROTOCOL = TCP)(HOST = ele1ole6)(PORT = 1522))
b) Positionner local_listener pour la base de données
[oracle@ele1ole6 ~]$ . oraenv ORACLE_SID = [cdb1212] ? cdb1212 The Oracle base remains unchanged with value /u01/app/oracle [oracle@ele1ole6 ~]$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.2.0 Production on Wed Aug 20 09:10:32 2014 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 set local_listener="LISTENER_CDB1212" ; System altered. SQL> show parameter local_listener NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ local_listener string LISTENER_CDB1212
Bien qu’étant un peu déçu de ne pas avoir une procédure plus simple et surtout plus rapide, il y a quand même quelques avantages avec cette architecture, par exemple je peux très bien avoir la même base (tant qu’il n’y a pas de nouvelles données ou des modifications) sur deux containers avec des versions différentes, ce qui laisse le temps pour valider votre applicatif par exemple. Ce n’est pas ce que dit Oracle qui précise que l’on ne peut avoir deux pluggable database de même nom sur deux containeurs racine sur le même serveur. Le secret : Un listener différent pour chaque PDB, car c’est en fait le nom de service qui est identique si on différencie l’accès via un numéro de port d’écoute différent cela fonctionne très bien.
Pas de miracle pour cette fois, mais de nouvelles possibilités, comme celle de réaliser le « plugin » d’une base dans un container au travers d’un dblink, une autre histoire à vous faire partager.