Friday 17 June 2016

Duplicate Database in Windows

A long time ago I put together notes on database duplication in Linux. Today I am posting more comprehensive notes for duplicating a database within a Windows environment.

The database I am cloning to (auxiliary) does not exist yet. The source database is production database (target) and I have copies of its most recent backup. The backup is a warm backup which I've copied from the server and placed in a location which which the duplication will call upon in the duplication process.

The destination environment has a listener which all development database register with so there are no details on setting up the listener.

This note is comprised of the following steps:
1. Create directories for auxiliary.
2. Create the pfile for auxiliary.
3. Create the service for auxiliary.
4. Create the spfile for auxiliary.
5. Adjust auxiliary so that it does not run production jobs upon opening
6. Duplicate the target to auxiliary using a recent warm backup from production
   -Specify the target and destination
   -Specify the databse file name conversion parameters
   -Specify the source backup location from which to duplicate from
   -Specify the log group
7. Disable auxiliary jobs
8. Adjust auxiliary to allow for the running of jobs after disabling the production jobs

Below are the descriptions of the <TAGS> found through the note:
<AUXILIARY_INSTANCE> - This is the name of the destination I want to restore a database into
<TARGET_INSTANCE> - This is the name of the database contained within the backup files used in the duplication process
<TARGET_INSTANCE_FOLDER> - This is the folder which holds my backup files used in the duplication process
<CONDITIONS FOR JOBS I WANT TO DISABLE> - This is a substitute for the conditions of which jobs I want to disable after the duplication. It is quite unlikely that jobs within a production database are meant to be running in a non-production environment.

1. Create directories for auxiliary.
The database will make use of the following locations.

REM Place for audits
mkdir -p E:\Oracle\admin\<AUXILIARY_INSTANCE>\adump
REM Place for datafiles
mkdir F:\Oracle\oradata\<AUXILIARY_INSTANCE>
REM Place for archivelogs
mkdir G:\Oracle\oradata\<AUXILIARY_INSTANCE>\archive

2. Create the pfile for auxiliary.
In command, open up notepad with the following command and paste the parameters into the file and save. Adjust accordingly.

notepad E:\oracle\product\11.2.0\dbhome_1\database\init<AUXILIARY_INSTANCE>.ora

*.audit_file_dest='E:\Oracle\admin\<AUXILIARY_INSTANCE>\adump'
*.audit_trail='db'
*.compatible='11.2.0.0.0'
*.control_files='F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL01.CTL','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL02.CTL','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL03.CTL'#Restore Controlfile
*.db_block_size=8192
*.db_domain=''
*.db_name='<AUXILIARY_INSTANCE>'#Reset to original value by RMAN
*.diagnostic_dest='E:\Oracle'
*.dispatchers='(protocol=TCP)'
*.fixed_date='none'
*.job_queue_processes=0
*.local_listener='LISTENER_LOCAL'
*.log_archive_dest_1='LOCATION=g:\oracle\oradata\<AUXILIARY_INSTANCE>\archive'
*.log_file_name_convert='F:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>'

*.log_archive_format='ARC%S_%R.%T'
*.memory_target=1063256064
*.open_cursors=300
*.processes=150
*.remote_login_passwordfile='EXCLUSIVE'
*.sec_case_sensitive_logon=FALSE
*.shared_servers=2
*.undo_tablespace='UNDOTBS1'
*.utl_file_dir='*'

*NOTE: The destination machine has a listener titled "LISTENER_LOCAL" that services all the instance on the machine. This is what *.LOCAL_LISTENER is all about.
This tells the AUXILIARY database "When you startup - I want you to register yourself with the listener on this machine titled LISTENER_LOCAL". If the environment doesn't have a common listener which instance can register with, then a static entry must be made in the listener.ora file for our new database - I will not cover this here.

*NOTE: Also note that you should have the *.log_file_name_convert parameter in your parameter list, especially if the target and auxiliary are on the same server. Should db_file_name_convert be omitted in both parameter and RMAN script, RMAN will restore the BK files as was and try to write the datafiles back to the location of the source. Datafiles about to be overwritten will halt the duplication process and RMAN will warn you that the destination files are in use by another instance, but this is not the case for redolog files. Duplicate database has, for me in the past, accidentally overwritten the source database redologs if one plays fast and loose with the details of the log file name conversion parameter - the duplicate command will default to the target databases log file location during control file creation if an administrator has not specified log conversion in some form or another.

3. Create the service for auxiliary.
I create the Windows service to represent the new instance.

set ORACLE_SID=<AUXILIARY_INSTANCE>


set ORACLE_HOME=E:\oracle\product\11.2.0\dbhome_1

oradim -new -SID <AUXILIARY_INSTANCE> -startmode manual -pfile 'E:\oracle\product\11.2.0\dbhome_1\database\init<AUXILIARY_INSTANCE>.ora'

OUTPUT
C:\Windows\system32>set ORACLE_SID=<AUXILIARY_INSTANCE>
C:\Windows\system32>set ORACLE_HOME=E:\oracle\product\11.2.0\dbhome_1
C:\Windows\system32>oradim -new -SID <AUXILIARY_INSTANCE> -startmode manual -pfile 'E:\oracle\product\11.2.0\dbhome_1\database\init<AUXILIARY_INSTANCE>.ora'
Instance created.

4. Create the spfile for auxiliary.
Create an spfile from the pfile used to start the database service.

create spfile from pfile;

OUTPUT
C:\Windows\system32>sqlplus /nolog
SQL*Plus: Release 11.2.0.3.0 Production on Fri Jun 17 08:57:50 2016
Copyright (c) 1982, 2011, Oracle.  All rights reserved.

SQL> conn / as sysdba
Connected to an idle instance.
SQL> create spfile from pfile;

File created.

SQL>

5. Adjust auxiliary so that it does not run production jobs upon opening in the development environment

alter system set job_queue_processes=0 scope=spfile;

OUTPUT
C:\Windows\system32>sqlplus /nolog

SQL*Plus: Release 11.2.0.3.0 Production on Fri Jun 17 09:06:20 2016

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

SQL> conn / as sysdba
Connected to an idle instance.
SQL> startup nomount;
ORACLE instance started.

Total System Global Area 1060585472 bytes
Fixed Size                  2261960 bytes
Variable Size             612371512 bytes
Database Buffers          440401920 bytes
Redo Buffers                5550080 bytes
SQL> alter system set job_queue_processes=0 scope=spfile;

System altered.

SQL> exit
Disconnected from Oracle Database 11g Release 11.2.0.3.0 - 64bit Production

C:\Windows\system32>


6. Duplicate the target to auxiliary using a recent warm backup from production
This is the part where the disks are put to work.
Because I am not duplicating directly from the target database but rather duplicating from a backup (datafiles, control files, archivelogfiles), I do not specify the TARGET parameter when connecting to RMAN. I also do not specify NOCATALOG because RMAN will default to NOCATALOG mode when catalog information is not specific in the RMAN connection command.

DB_FILE_NAME_CONVERT is used to automatically rename the restored backup files to a new location: considering the auxiliary environment is NOT the production environment and the drives are not the same, I have provided the convert to suit the destination environments layout.

BACKUP LOCATION is a neat little parameter that tells RMAN where to look for the backup files of TARGET. This does away with the need to CATALOG the backup pieces prior to duplication.

LOGFILE tells RMAN where to create the redo logfiles and their sizes.

rman auxiliary / 
run {
    DUPLICATE DATABASE <TARGET_DATABASE> to "<AUXILIARY_INSTANCE>" 
    DB_FILE_NAME_CONVERT='G:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','H:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','E:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','D:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','F:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>' 
    BACKUP LOCATION='C:\BACKUP\<TARGET_INSTANCE_FOLDER>' 
    LOGFILE 
      'F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\redo01.log' size 10M, 
      'F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\redo02.log' size 10M, 
      'F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\redo03.log' size 10M; 
    }
exit 

OUTPUT

RMAN> run {
2>     DUPLICATE DATABASE <TARGET_DATABASE> to "<AUXILIARY_INSTANCE>"
3>     DB_FILE_NAME_CONVERT='G:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','H:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','E:\ORACLE\ORADATA\G
DATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>','F:\ORACLE\ORADATA\<TARGET_DATABASE>','F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>'
4>     BACKUP LOCATION='C:\BACKUP\<TARGET_INSTANCE_FOLDER>'
5>     LOGFILE
6>       'F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\redo01.log' size 10M,
7>       'F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\redo02.log' size 10M,
8>       'F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\redo03.log' size 10M;
9>      }

Starting Duplicate Db at 17-JUN-16

contents of Memory Script:
{
   sql clone "alter system set  db_name =
 ''<TARGET_DATABASE>'' comment=
 ''Modified by RMAN duplicate'' scope=spfile";
   sql clone "alter system set  db_unique_name =
 ''<AUXILIARY_INSTANCE>'' comment=
 ''Modified by RMAN duplicate'' scope=spfile";
   shutdown clone immediate;
   startup clone force nomount
   restore clone primary controlfile from  'C:\BACKUP\<TARGET_INSTANCE_FOLDER>\<TARGET_DATABASE>_BRR7VP4C_1_1.RMAN';
   alter clone database mount;
}
executing Memory Script

sql statement: alter system set  db_name =  ''<TARGET_DATABASE>'' comment= ''Modified by RMAN duplicate'' scope=spfile

sql statement: alter system set  db_unique_name =  ''<AUXILIARY_INSTANCE>'' comment= ''Modified by RMAN duplicate'' scope=spfile
executing Memory Script

sql statement: alter system set  db_name =  ''<TARGET_DATABASE>'' comment= ''Modified by RMAN duplicate'' scope=spfile

sql statement: alter system set  db_unique_name =  ''<AUXILIARY_INSTANCE>'' comment= ''Modified by RMAN duplicate'' scope=spfile

Oracle instance shut down

Oracle instance started

Total System Global Area    1060585472 bytes

Fixed Size                     2261960 bytes
Variable Size                612371512 bytes
Database Buffers             440401920 bytes
Redo Buffers                   5550080 bytes

Starting restore at 17-JUN-16
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=129 device type=DISK
channel ORA_AUX_DISK_1: restoring control file
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:03
output file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL01.CTL
output file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL02.CTL
output file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL03.CTL
Finished restore at 17-JUN-16

database mounted
released channel: ORA_AUX_DISK_1
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=129 device type=DISK
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:03
output file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL01.CTL
output file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL02.CTL
output file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\CONTROL03.CTL
Finished restore at 17-JUN-16

database mounted
released channel: ORA_AUX_DISK_1
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=129 device type=DISK

........................................................

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 F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\SYSTEM01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00002 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\SYSAUX01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00003 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\UNDOTBS01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00004 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\USERS01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00005 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\FINDATADM1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00006 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\FINDATAUDIT1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00007 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\FINDATINT1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00008 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\FININDADM1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00009 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\FININDINT1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00010 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\AUDIT_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00011 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPDATADMD1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00012 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPDATADMD2_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00013 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPDATADMS_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00014 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINTERFACE1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00015 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPDATOPSD1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00016 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPDATOPSD2_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00017 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPDATOPSS_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00018 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDADMD1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00019 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDADMD2_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00020 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDADMS_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00021 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDINTERFACE1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00022 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDOPSD1_1.DBF
channel ORA_AUX_DISK_1: restoring datafile 00023 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDOPSD2_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00024 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDOPSS.DBF
channel ORA_AUX_DISK_1: restoring datafile 00025 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPUSERS1_01.DBF
channel ORA_AUX_DISK_1: restoring datafile 00026 to F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\UNDOTBS02.DBF
channel ORA_AUX_DISK_1: reading from backup piece C:\BACKUP\<TARGET_INSTANCE_FOLDER>\<TARGET_DATABASE>_BQR7VNJU_1_1.RMAN
......................
input datafile copy RECID=20 STAMP=914752023 file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDINTERFACE1_01.DBF
datafile 22 switched to datafile copy
input datafile copy RECID=21 STAMP=914752023 file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDOPSD1_1.DBF
datafile 23 switched to datafile copy
input datafile copy RECID=22 STAMP=914752023 file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDOPSD2_01.DBF
datafile 24 switched to datafile copy
input datafile copy RECID=23 STAMP=914752023 file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPINDOPSS.DBF
datafile 25 switched to datafile copy
input datafile copy RECID=24 STAMP=914752023 file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\GPUSERS1_01.DBF
datafile 26 switched to datafile copy
input datafile copy RECID=25 STAMP=914752023 file name=F:\ORACLE\ORADATA\<AUXILIARY_INSTANCE>\UNDOTBS02.DBF

contents of Memory Script:
{
   Alter clone database open resetlogs;
}
executing Memory Script

database opened
Finished Duplicate Db at 17-JUN-16

RMAN>

While the database is restoring, I can monitor the duplication progress using v$session_longops using another database session. The RMAN process registers its block restoration effort in the v$session_longops dynamic view. How handy is that. In another cmd window, I run the following connected to the auxiliary instance

select message from v$session_longops;

OUTPUT
E:\oracle\glassfish4\bin>set ORACLE_SID=<AUXILIARY_INSTANCE>

E:\oracle\glassfish4\bin>sqlplus /nolog

SQL*Plus: Release 11.2.0.3.0 Production on Fri Jun 17 09:43:06 2016

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

SQL> conn / as sysdba
Connected.
SQL> select message from v$session_longops;

MESSAGE
--------------------------------------------------------------------------------
RMAN: aggregate input: restore 421: 4915871 out of 0 Blocks done
RMAN: full datafile restore: Set Count 11642: 5212774 out of 5744384 Blocks done

SQL> /

MESSAGE
--------------------------------------------------------------------------------
RMAN: aggregate input: restore 421: 5260134 out of 0 Blocks done
RMAN: full datafile restore: Set Count 11642: 5306598 out of 5744384 Blocks done

SQL> /

MESSAGE
--------------------------------------------------------------------------------
RMAN: aggregate input: restore 421: 5260134 out of 0 Blocks done
RMAN: full datafile restore: Set Count 11642: 5319142 out of 5744384 Blocks done

SQL>

See how the block count increases, this is my proverbial progress bar for observation

7. Disable auxiliary jobs
Here I disable the production jobs before re-enabling the job parameter.

conn / as sysdba
BEGIN
  FOR r_jobs IN (SELECT job 
                   FROM dba_jobs 
                  WHERE <CONDITIONS FOR JOBS I WANT TO DISABLE>
                  )
  LOOP
    DBMS_JOB.BROKEN(r_jobs.job,TRUE);
  END LOOP;
  
  FOR r_scheduler_jobs IN (SELECT owner,
                                  job_name 
                             FROM SYS.dba_scheduler_jobs 
                            WHERE  <CONDITIONS FOR JOBS I WANT TO DISABLE>
                           )
  LOOP
    DBMS_SCHEDULER.DISABLE('"' || r_scheduler_jobs.owner  || '"."' || r_scheduler_jobs.job_name || '"',TRUE);
  END LOOP;

END;
/

OUTPUT
SQL> BEGIN
  2    FOR r_jobs IN (SELECT job
  3                     FROM dba_jobs
  4                    WHERE <CONDITIONS FOR JOBS I WANT TO DISABLE>
  5                    )
  6    LOOP
  7      DBMS_JOB.BROKEN(r_jobs.job,TRUE);
  8    END LOOP;
  9
 10    FOR r_scheduler_jobs IN (SELECT owner,
 11                                    job_name
 12                               FROM SYS.dba_scheduler_jobs
 13                              WHERE <CONDITIONS FOR JOBS I WANT TO DISABLE>
 14                             )
 15    LOOP
 16      DBMS_SCHEDULER.DISABLE('"' || r_scheduler_jobs.owner  || '"."' || r_scheduler_jobs.job_name || '"',TRUE);
 17    END LOOP;
 18
 19  END;
 20  /

PL/SQL procedure successfully completed.

SQL> select owner, job_name, enabled from dba_scheduler_jobs where enabled = 'TRUE';

OWNER                          JOB_NAME                       ENABL
------------------------------ ------------------------------ -----
SYS                            PURGE_LOG                      TRUE
SYS                            ORA$AUTOTASK_CLEAN             TRUE
SYS                            DRA_REEVALUATE_OPEN_FAILURES   TRUE
ORACLE_OCM                     MGMT_CONFIG_JOB                TRUE
ORACLE_OCM                     MGMT_STATS_CONFIG_JOB          TRUE
SYS                            BSLN_MAINTAIN_STATS_JOB        TRUE
SYS                            RSE$CLEAN_RECOVERABLE_SCRIPT   TRUE
SYS                            SM$CLEAN_AUTO_SPLIT_MERGE      TRUE
EXFSYS                         RLM$EVTCLEANUP                 TRUE
EXFSYS                         RLM$SCHDNEGACTION              TRUE
SYS                            AUDIT_PURGE                    TRUE

11 rows selected.

SQL>

Only the system jobs are left running.

8. Adjust auxiliary to allow for the runnign of jobs after disabling the production jobs
Now that the jobs are disabled, I can go ahead and allow the system to run jobs again.

alter system set job_queue_processes=5 scope=both;

OUTPUT
SQL> alter system set job_queue_processes=5 scope=both;

System altered.

SQL>

All done.

No comments:

Post a Comment