Showing posts with label migration. Show all posts
Showing posts with label migration. Show all posts

Monday, September 09, 2013

My Experience of Data Pump Export and Import for Database Migration

Recently I have carried out a test of using Data Pump Export and Import utilities to migrate a 17 TB database from Solaris to Linux platform, also from single-instance, conventional file system to a two-node RAC on ASM. During the exercise I have learned and become more familiar with quite a few interesting features or options of Data Pump Export and Import utilites and encountered a few difficulties as well.

The first obstacle I met was that I was unable to do Data Pump Export to the NFS storage. We have the NFS storage that is shared between the Solaris and Linux server. At first I tried to perform Data Pump Export to the NFS storage directly. Unfortunately, the job was just stuck there for long time. Having researched this issue for a while and tried the options mentioned in a MOS note (See References [1]) with the help of a SA, I just could not get this worked out. Finally we decided to export to the local file system first then move the dump files to the NFS. I was able to move about 150 GB dump file per hour. Fortunately, the Data Pump Import from NFS storage did not pose any problems.

Table mode Data Pump Export and Import were used in the test. Large tables were typically exported or imported individually and smaller tables were grouped together into several batches. For each large table or a group of smaller tables, I prepared the corresponding parameter files with parallel option if appropriate. In the Import job, I always excluded the index, constraint and statistics. I used SQLFILE option of the impdp command to extract the DDL commands related to the tables, including create table, index and constraint statements etc. Those DDLs were executed after the Import with parallel option for index creation and "ENABLE NOVALIDATE" for constraints typically. Therefore the database migration actually consisted of multiple tables migration jobs. For each tables migration, I performed and recorded the timing of the following steps: export, move dump file to NFS, import, DDLs for index etc. Those tables migration jobs were overlapped as two or three of them were executed at the same time and could be in different steps.

Shortly after the onset of the test I found out that Data Pump Export was extremely slow on a big table with lob column. The  export job was unable to run in parallel regardless of the parallel setting. The segment sizes of this big table are 237 GB and 382 GB for table and lob respectively. The table uses a sequence-based PK column called "EMAIL_SEQ_ID". To speed up the export, I started 23 export jobs at the same time, each job exported a particular range of rows based on the PK. The key is to use the QUERY option for the expdp command. The QUERY option contains a WHERE clause that specifies the PK range. Finally I was able to export this table in 30 hours, move the 420 GB dump files in 2 hours, import in about 15 hours and execute DDL for indexes etc in 2 hours. It is worth noting that although we can perform the lob table export job in parallel by such an approach, we cannot do the same for import. The import job will hold a TM lock for the table, so only one import job can run at a time. I used this approach for several big lob tables. Appendix showed example Shell script to prepare expdp or impdp parfile. By the way, later I found that unable to export in parallel for lob table is a known issue in the Oracle community. (see Reference [3]). A blog post suggested using rowid based approach to separate the rows of lob tables. (see Reference [4])

Occasionally I made mistakes and needed to terminate an export or import job. I found it very convenient to use KILL_JOB command in the interactive mode. First, I need to know the job name either from log file or from dba_datapump_jobs view. Then I can enter the interactive mode using attach option:

expdp / attach=[job_name]

Then I issued "KILL_JOB" command. Note when using KILL_JOB to the expdb, all dump files will be wiped out.

During the test, I have also learned that Data Pump Import can be done through db link. When specifying a source database link for the NETWORK_LINK option of impdp command, import job will retrieve data from the db link, and write the data directly to the target database There are no dump files involved.

I have mentioned previously SQLFILE option can be used to extract DDLs. But this option only available for impdp. Suppose I have a table in a database and I want to extract DDLs related to this table including indexes, constraints, object grants, comments, triggers etc associated with it, how should I do? Previously I always use DBMS_METADATA package for such tasks. If we create a db link to the database itself, we can use impdp with NETWORK_LINK and SQLFILE options to accomplish it very neatly.

Using export/import to migrate the database has one advantage over Transportable Tablespace approach at least: it allows the re-organization of tables and indexes. i.e. it is easy to move tables and indexes to different tablespaces if desired.

I completed the 17 TB database migration with the size of about 12 TB in the target database in about a month. The test was interrupted by other tasks with higher priority. I did total 17 tables migrations to complete the whole database migration. Ordered by end-to-end time (including export, move to NFS, import, DDL steps), they were refered to as as batch 1 to 17 here:

batch   time (hours) 
-----   ----------- 
1        50
2        30
3        25
4        24
5        21
6        16
7        15
8        14
9        11
10       10
11       10
12       9.5
13       5.5
14       5
15       3.5
16       3
17       3
------------



Based on above timing, if I perform the migration task as continuely as possible, I may be able to compete it in 5-7 days. The ultimate goal is to do a zero-down time migration. We plan to use oracle Golden Gate to caputure the changes at source during the database migration. So my next task will be investiagating whether this is possible in practise in our environment.

References:
[1] 781349.1 - ORA-27054: NFS file system where the file is created or resides is not mounted with correct options [ID 781349.1])
[2] Sample Export and Import parameter files:
 -- expdp.par  ----


 DIRECTORY=dpump_dir3
 DUMPFILE=dpump_dir3:email%U_q2.dmp
 TABLES=TTQ_GMPX.TTQ_EMAIL_EVENT_DETAILS
 LOGFILE=dpump_dir3:TTQ_EMAIL_EVENT_DETAILS_q2.log
 #PARALLEL=20
 FILESIZE=5G
 JOB_NAME=exp_email_q2
 QUERY="WHERE email_seq_id >=2*200000000   and email_seq_id < 3*200000000"


  -- impdp.par ----

 DIRECTORY=dpump_dir
 DUMPFILE=dpump_dir:email%U_q2.dmp
 TABLES=TTQ_GMPX.TTQ_EMAIL_EVENT_DETAILS
 TABLE_EXISTS_ACTION=APPEND
 LOGFILE=dpump_dir:TTQ_EMAIL_EVENT_DETAILS_q2_imp.log
 PARALLEL=2
 JOB_NAME=imp_email_q2
 EXCLUDE=index,constraint,statistics
 #EXCLUDE=statistics
 transform=storage:n,oid:n
 CLUSTER=NO

[3] Bug 5599947 - Export Data Pump is slow when table has a LOB column - Defect: Bug:5599947 "DATAPUMP EXPORT VERY SLOW"

[4] http://jensenmo.blogspot.com/2012/10/optimising-data-pump-export-and-import.html

[5] Some other references:
Master Note for Data Pump [ID 1264715.1]
Checklist For Slow Performance Of DataPump Export (expdp) And Import (impdp) [ID 453895.1]
Parallel Capabilities of Oracle Data Pump [ID 365459.1]


Appendix - sample shell script to generate expdp/impdp par file for big lob table

#!/bin/ksh
i=21
while [[ $i -le 43 ]];do
 
  ((j=i+1))
  PARFILE="EMAIL_CONTENT_q$i.par"
  echo "DIRECTORY=dpump_dir3" > $PARFILE 
  echo "DUMPFILE=dpump_dir3:ecntnt_q${i}_%U.dmp" >> $PARFILE 
  echo "TABLES=TTQ_GMPX.EMAIL_CONTENT" >> $PARFILE
  echo "LOGFILE=dpump_dir3:EMAIL_CONTENT_q$i.log" >> $PARFILE 
  echo "FILESIZE=10G" >> $PARFILE
  echo "JOB_NAME=exp_ecntnt_q$i" >> $PARFILE
  echo "QUERY=\"WHERE email_seq_id > $i * 2000000  and email_seq_id <= $j * 2000000\"">> $PARFILE
 
 
  echo "i=$i"
  echo "j=$j"
  ((i=i+1))
done

--- sample script to generate impdp par file for big lob table -----------------

i=6
while [[ $i -le 43 ]];do
 
  ((j=i+1))
  PARFILE="EMAIL_CONTENT_imp_q$i.par"
  echo "DIRECTORY=dpump_dir" > $PARFILE 
  echo "DUMPFILE=ecntnt_q${i}_%U.dmp" >> $PARFILE 
  echo "TABLES=TTQ_GMPX.EMAIL_CONTENT" >> $PARFILE
  echo "TABLE_EXISTS_ACTION=APPEND" >> $PARFILE
  echo "LOGFILE=EMAIL_CONTENT_q${i}_imp.log" >> $PARFILE 
  echo "JOB_NAME=imp_ecntnt_q${i}" >> $PARFILE
  echo "#EXCLUDE=index,constraint,statistics" >> $PARFILE
  echo "EXCLUDE=statistics" >> $PARFILE 
  echo "transform=storage:n,oid:n" >> $PARFILE
  echo "CLUSTER=NO" >> $PARFILE
 
 
  echo "i=$i"
  echo "j=$j"
  ((i=i+1))
done


Thursday, August 29, 2013

Practise Migration Through Transportable Tablespace from non-ASM to ASM

References:

http://relcon.typepad.com/relatively_speaking/2009/10/migrating-an-oracle-database-from-solaris-to-linux.html

http://www.oracle.com/technetwork/database/features/availability/maa-wp-11g-platformmigrationtts-129269.pdf


Source database OS is Solaris and using OS file system. Target database is in on Linux and ASM.

Steps:

1. Check that platforms are compatible.

Run this query on the database you want to migrate from and it will list the platforms you can migrate to:

select * from V$TRANSPORTABLE_PLATFORM;


check the value of ENDIAN_FORMAT, if you are migrating from one format to another you are going to need to convert your database files, so for example going from Solaris to Linux you will need to convert.
PLATFORM_ID PLATFORM_NAME                        ENDIAN_FORMAT
----------- ------------------------------------ --------------
          6 AIX-Based Systems (64-bit)           Big
         16 Apple Mac OS                         Big
         21 Apple Mac OS (x86-64)                Little
         19 HP IA Open VMS                       Little
         15 HP Open VMS                          Little
          5 HP Tru64 UNIX                        Little
          3 HP-UX (64-bit)                       Big
          4 HP-UX IA (64-bit)                    Big
         18 IBM Power Based Linux                Big
          9 IBM zSeries Based Linux              Big
         10 Linux IA (32-bit)                    Little
         11 Linux IA (64-bit)                    Little
         13 Linux x86 64-bit                     Little
          7 Microsoft Windows IA (32-bit)        Little
          8 Microsoft Windows IA (64-bit)        Little
         12 Microsoft Windows x86 64-bit         Little
         17 Solaris Operating System (x86)       Little
         20 Solaris Operating System (x86-64)    Little
          1 Solaris[tm] OE (32-bit)              Big
          2 Solaris[tm] OE (64-bit)              Big
   

2. You can only migrate tablespaces to a database which uses the same character set and national charcter set, so check if you are migrating to an existing database or make sure to use the same values if you are building a new database.
 srcdb> SELECT * FROM nls_database_parameters order by 1;

 PARAMETER                      VALUE
 ------------------------------ ----------------------------------------
 NLS_CALENDAR                   GREGORIAN
 NLS_CHARACTERSET               WE8ISO8859P1
 NLS_COMP                       BINARY
 NLS_CSMIG_SCHEMA_VERSION       2
 NLS_CURRENCY                   $
 NLS_DATE_FORMAT                DD-MON-RR
 NLS_DATE_LANGUAGE              AMERICAN
 NLS_DUAL_CURRENCY              $
 NLS_ISO_CURRENCY               AMERICA
 NLS_LANGUAGE                   AMERICAN
 NLS_LENGTH_SEMANTICS           BYTE
 NLS_NCHAR_CHARACTERSET         AL16UTF16
 NLS_NCHAR_CONV_EXCP            FALSE
 NLS_NUMERIC_CHARACTERS         .,
 NLS_RDBMS_VERSION              11.2.0.3.0
 NLS_SORT                       BINARY
 NLS_TERRITORY                  AMERICA
 NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
 NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
 NLS_TIME_FORMAT                HH.MI.SSXFF AM
 NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR

 21 rows selected.



 tgtdb> SELECT * FROM nls_database_parameters order by 1;
  
 PARAMETER                      VALUE
 ------------------------------ ----------------------------------------
 NLS_CALENDAR                   GREGORIAN
 NLS_CHARACTERSET               WE8MSWIN1252
 NLS_COMP                       BINARY
 NLS_CURRENCY                   $
 NLS_DATE_FORMAT                DD-MON-RR
 NLS_DATE_LANGUAGE              AMERICAN
 NLS_DUAL_CURRENCY              $
 NLS_ISO_CURRENCY               AMERICA
 NLS_LANGUAGE                   AMERICAN
 NLS_LENGTH_SEMANTICS           BYTE
 NLS_NCHAR_CHARACTERSET         AL16UTF16
 NLS_NCHAR_CONV_EXCP            FALSE
 NLS_NUMERIC_CHARACTERS         .,
 NLS_RDBMS_VERSION              11.2.0.3.0
 NLS_SORT                       BINARY
 NLS_TERRITORY                  AMERICA
 NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
 NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
 NLS_TIME_FORMAT                HH.MI.SSXFF AM
 NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
  
 20 rows selected.

WE8MSWIN1252 is a superset of WE8ISO8859P1:
Difference between WE8MSWIN1252 and WE8ISO8859P1 characterset (Doc ID 341676.1)

Some problems repored from WE8ISO8859P1 to WE8MSWIN1252: https://forums.oracle.com/message/9885182#9885182


3. Assuming you are good to go you need to determine which tablespaces hold the data you want to transport and then double check that the list is self-contained, execute this PL/SQL procedure to check the tablespaces you plan to migrate:
 sys@srcdb> execute sys.dbms_tts.transport_set_check('tbs1_data,tbs1_indx',true);
  
 PL/SQL procedure successfully completed.
  
 sys@srcdb> select * from sys.transport_set_violations;
  
 no rows selected

    
   Note: these violations must be resolved before the tablespaces can be transported. 

4. The tablespaces need to be in READ ONLY mode in order to successfully run a transport tablespace export:

alter tablespace tbs1_data read only;

alter tablespace tbs1_indx read only;


5. Export the metadata.
 
$ exp userid=\'/ as sysdba\'  file=tbs_exp.dmp log=tba_exp.log transport_tablespace=y tablespaces=tbs1_data,tbs1_indx 
 
Export: Release 11.2.0.3.0 - Production on Thu Aug 29 14:42:18 2013
 
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 - 64bit Production
With the Partitioning, Oracle Label Security, Oracle Database Vault and Real Application Testing options
Export done in US7ASCII character set and AL16UTF16 NCHAR character set
server uses WE8ISO8859P1 character set (possible charset conversion)
Note: table data (rows) will not be exported
About to export transportable tablespace metadata...
For tablespace TBS1_DATA ...
. exporting cluster definitions
. exporting table definitions
. . exporting table                             EC
EXP-00091: Exporting questionable statistics.
For tablespace TBS1_INDX ...
. exporting cluster definitions
. exporting table definitions
. exporting referential integrity constraints
. exporting triggers
. end transportable tablespace metadata export
Export terminated successfully with warnings.


6. copy the metadata export, datafiles and any schema exports to the new host

cp tbs1_data_01.dbf /oradbbackup02_NFS/landingpad/dump
cp tbs1_indx_01.dbf /oradbbackup02_NFS/landingpad/dump
cp tbs_exp.dmp /oradbbackup02_NFS/landingpad/dump

Note: /oradbbackup02_NFS is NFS mount at source, and at target the mount is /oradbbackup02

7. convert the datafiles to new platform format using RMAN, in this example we will put the converted datafiles into an ASM instance:
rman  target / 

convert datafile 
  '/oradbbackup02/landingpad/dump/tbs1_data_01.dbf', 
  '/oradbbackup02/landingpad/dump/tbs1_indx_01.dbf'
  from platform 'Solaris[tm] OE (64-bit)' 
  format '+DATA_05' 
  parallelism 4;


Starting conversion at target at 29-AUG-13
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=118 instance=tgtdb2 device type=DISK
allocated channel: ORA_DISK_2
channel ORA_DISK_2: SID=124 instance=tgtdb2 device type=DISK
allocated channel: ORA_DISK_3
channel ORA_DISK_3: SID=137 instance=tgtdb2 device type=DISK
allocated channel: ORA_DISK_4
channel ORA_DISK_4: SID=151 instance=tgtdb2 device type=DISK
channel ORA_DISK_1: starting datafile conversion
input file name=/oradbbackup02/landingpad/dump/tbs1_data_01.dbf
channel ORA_DISK_2: starting datafile conversion
input file name=/oradbbackup02/landingpad/dump/tbs1_indx_01.dbf
converted datafile=+DATA_05/tgtdb/datafile/tbs1_data.316.824728129
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:04
converted datafile=+DATA_05/tgtdb/datafile/tbs1_indx.317.824728131
channel ORA_DISK_2: datafile conversion complete, elapsed time: 00:00:04
Finished conversion at target at 29-AUG-13



8. plug the tablespace into the target database, check the ASM instance to get the names of the converted datafiles:



  -- imp.par
file=tbs_exp.dmp
log=tts.log
transport_tablespace=Y
datafiles= '+DATA_05/tgtdb/datafile/tbs1_data.316.824728129'
,'+DATA_05/tgtdb/datafile/tbs1_indx.317.824728131'


$ imp userid=\'/ as sysdba\' parfile=imp.par


 
Import: Release 11.2.0.3.0 - Production on Thu Aug 29 12:59:02 2013
 
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 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Tes
 
Export file created by EXPORT:V11.02.00 via conventional path
About to import transportable tablespace(s) metadata...
import done in US7ASCII character set and AL16UTF16 NCHAR character set
import server uses WE8MSWIN1252 character set (possible charset conversion)
. importing SYS's objects into SYS
. importing SYS's objects into SYS
. importing OPS$ORACLE's objects into OPS$ORACLE
. . importing table                           "EC"
. importing SYS's objects into SYS
Import terminated successfully without warnings.

9. set the imported tablespaces to read write:

alter tablespace tbs1_data read write;
alter tablespace tbs1_indx read write;