一、前言:

  本文记录了,一次实际使用数据泵工具expdp/impdp的迁移数据库的过程。
   源库:   为11g R2(11.1.0.6),os为windows,
   目标库:为10gR2(10.2.0.4), os为AIX 6.1。
  迁移的平台是异构的(从windows到aix)且版本不相同,无法通过物理备份进行还原,只能使用逻辑方式进行迁移,目前有两种选择:
   a.传统导入/导出的工具(exp/imp),优点是简单易用,也有一定的经验积累。缺点是没有并行能力,速度较慢。迁移的医院,整个数据库虽然只有80g,但由于源库的硬件使用了长达6年,性能很差,无法在规定停机的时间内完成迁移;还有就是无法很多新的数据类型。
   b.10g或以上版本提供的数据泵工具(expdp/impdp)。相比传统的exp/imp工具,速度有质的变化,但由于工具较新,稳定性与个人使用经验相对欠缺。
   
二、关键技术:   
  综合对比,我决定选择使用数据泵来实施本次迁移。其中主要利用了几个数据泵的关键待性:
   a.跨版本迁移数据库;使用version参数来实现,version参数的格式如下:
     version='发行版本串',比如version='10.2.0',使用这个参数后,将不会导出version参数指定的不支持的数据库对象类型;由于Oracle从10g才开始出现数据泵工具,因此无法使用将version指定为'10.1'以下的版本。这样低版本的数据泵工具就可以识别高版本导出的dump文件。
   b.并行导出/导入的能力,通过parallel参数来实现。
    我认为并行操作是expdp/impdp的最吸引人的特性之一,可以最大的利用io与cpu资源,来加快导出/导入的响应的时间。开启并行后,oracle会将大于250m的表,分解成多个数据段,由不同的从属进程进行IO操作。使用并行时,需要注意的点:
       1).并行进程的个数,一般可以cpu数据量的2倍或与cpu数量相同。可以根据系统资源的情况灵活调整。
       2).并行进程与dump文件集的关系。dump文件集中的文件数量不要少于并行进程的数量,否则可能导致多个进程争用dump文件的情况。可以在dumpfile参数中使用"%U"占位符来自动生成dump文件集。比如指定dumpfile=expdp_full%U.dmp生成的文件名会是expdp_full01.dmp,xpdp_full02.dmp,...以此类推,文件个数与并行进程数相同。
       3).元数据(Metadata,也就是数据库对象的定义,比如存储过程、函数、表定义等)无法使用并行进程来创建,但package body除外。
       4).含有lob对象的表无法使用并行。
       5).在导入时,创建索引imp也可以自动使用并发。     
       
三、实际的迁移过程    

1.停止源服务器上db,估计5分钟,由于是集群环境,使用srvctl命令更为简单:
  srvctl stop database -d orcl 
  
2.停止监听,可以在一个节点上执行,两个节点的监听都需要停止;然后重新打开数据库,经过这一步后,客户端将无法连接到数据库了。
  srvctl stop  listener -n nodename
  srvctl start instance -d orcl -i orcl1
  
3.只启动一个实例,使用export导出数据库,由于当前是11g数据库,需要指定版本(version参数):

  export ORACLE_SID=orcl1    
  --将全库与电子病历图形分开导出,同时运行。全库的会先导出完成,导出完成即可传递数据和在小机端进行导入操作。  
  expdp system/oracle  DUMPFILE=expdp_full_%U.dmp DIRECTORY=dump    LOGFILE=expdpfull.log FULL=y parallel=8 version='10.2.0' exclude=TABLE:\"IN (select table_name from dba_tables where table_name='电子病历图形' and owner='ZLHIS')\"  
  expdp system/oracle  DUMPFILE=expdp_dzbltxs.dmp DIRECTORY=dump   LOGFILE=expdp_dzbltx.log tables=ZLHIS.电子病历图形  version='10.2.0'
    
  整个数据库中,电子病历图形是最大的,且这个表包括了lob列,无法使用并行操作。实际过程也证明,除了这个表的全库导出,只需要1个小时,而这一表的导出就需要3个小时。这样,分开来导出就不需要电子病历图表这个表导出,即可开始导入操作。利用这个时间差,可极大的减少总的操作时间。
  
4.使用ftp命令传输备份文件,一定注意使用二进制方式传输,估计40分钟:

  h:
  cd h:\expdp   
  ftp 192.168.0.162    
  cd /backup
  binary 
  mput expdpfull01.dmp   
  
  使用ftp传输数据,可以使用一些ftp工具,但切记使用二进制方式进行传输,否则文件dump传递到小型机后可能不可用。
  
5.在小型机上只开启一个实例,开始导入数据库,使用并行度8,正式库的数据导入准备工作在数据导出期间先进行,这些工作主要为了加快导入的速度做的一些调整:

   a.关闭归档,减少归档的文件操作,可一定程度上减少停机时间
 
   b.创建表空间同时;加大undo表空间到20g,temp表空间为10g; 原库有一个temp01的临时表空间,注意导入完成后,删除这个临时表空间。
     1)先创建表空间,执行/backup/create_ts.sql脚本。
     2)将表空间设置为自动增长,这是生成修改脚本的sql:
     select 'alter database datafile '||file#||'  autoextend on ;' from v$datafile
     select 'alter database tempfile '||file#||'  autoextend on ;' from v$tempfile 
     在Oracle对datafile与tempfile都可以使用文件编号(file#)来代替完整的文件名,以此来简化我们的命令。
     3)加大undo段与临时段
     alter database  datafile '+DATA/orcl/UNDOTBS01.DBF'  resize 20g; 
     alter database  tempfile '+DATA/orcl/temp01.DBF'     resize 10g; 
   加大temp表空间是因为,创建索引时,需要大量地的排序操作,当内存中无法完成排序时,需要使用temp表空间来完成排序。

   c.关闭pga自动管理,并加大*_area_size参数为100m 
    alter system set workarea_size_policy=manual;
    alter system set sort_area_size=104857600; 
    创建索引时,需要大量地的排序操作,加大排序区以使,排序尽量在内存中完成,可以起到比较明显的加块索引创建的效果。但Oracle 10g默认是使用pga自动管理,无法手动设置排序区,所以需要先关闭pga自动管理。
    
    
   d.创建目录对象 
    create directory dump as '/backup'; 
    grant read,write on directory dump to system; 
    数据泵工具是服务端工具,导入/导出进程的io操作只能在oracle服务端,需要创建一个目录对象来保存dump文件与log文件。
    
  e.加一组4g的logfile ,导入时,会产生大量的redo日志,加一组这样的日志,可以减少日志切换的频繁,以加快导入速度。
    alter database add logfile thread 1 group 5  '+DATA/orcl/redo05.log' size 4g; 
    
   f.执行导入,同样使用并行操作,两个dump文件分开导入。 
    export ORACLE_SID=orcl1  
    impdp system/zlsoft  DUMPFILE=expdpfull%U.dmp  directory=dump  full=y  LOGFILE=impdpfull.log  parallel=8   exclude=SCHEMA:\" in ('SYS','SYSTEM','OUTLN','MGMT_VIEW','FLOWS_FILES','MDSYS','ORDSYS','EXFSYS','DBSNMP','WMSYS','WKSYS','WK_TEST','CTXSYS','ANONYMOUS','SYSMAN','XDB','WKPROXY','ORDPLUGINS','FLOWS_030000','OWBSYS','SI_INFORMTN_SCHEMA','OLAPSYS','SCOTT','ORACLE_OCM','TSMSYS','XS$NULL','MDDATA','DIP','APEX_PUBLIC_USER','SPATIAL_CSW_ADMIN_USR','SPATIAL_WFS_ADMIN_USR')\"
    impdp system/zlsoft  DUMPFILE=expdp_dzbltx.dmp  directory=dump   LOGFILE=impdp_dzblt.log tables=ZLHIS.电子病历图形 parallel=4
    测试时间3.5小时
    
    
6.收集统计信息,40分钟,下面已经可以使用.
  
  --数据字典统计信息,这个脚本的规则是,大于50m的对象就使用并行度为8,采样比5%的收集方式来加快收集统计信息的速度
  exec dbms_stats.gather_dictionary_stats(estimate_percent => 100,degree => 4,cascade => true);
  --ZLHIS对象,大于50m的表使用8的并发,并采样5%:
  select 'exec dbms_stats.gather_table_stats(ownname => ''ZLHIS'',tabname => '''||table_name
       ||''',estimate_percent => '||decode(sign(b.BYTES/1024/1024-50),1,5,100)  ||',method_opt => ''for all indexed columns size auto'',cascade => true,force => true,degree => '
       ||decode(sign(b.BYTES/1024/1024-50),1,8,1)||');'
  from dba_tables a,dba_segments b where a.table_name=b.segment_name and b.segment_type='TABLE'
  and  a.owner='ZLHIS' 
  order by b.BYTES desc 
  
  --ZLTOOLS对象,采样100%
  exec dbms_stats.gather_schema_stats(ownname => 'ZLTOOLS',estimate_percent => 100,degree => 4,cascade => true,force => true);
  
  特别强调一点,数据迁移后,数据经过了重整,重新收集统计信息是一个保证cbo得到最优执行计划的必须保证。
  
7.清除特殊设置,20分钟
  a.设置sort_area_size为默认值,同时开启pga自动管理。          
      alter system set sort_area_size=65536  scope=spfile;
      alter system set hash_area_size=131072;
      alter system set workarea_size_policy=auto;
      shutdown immediate;
      startup;
  b.恢复undo与temp表空间为正常值
      alter database  datafile '+DATA/orcl/UNDOTBS01.DBF'  resize 8g;
      alter database  tempfile '+DATA/orcl/temp01.DBF'     resize 4g;
      
      --删除原来的temp01表空间,使用默认的temp表空间
      select 'alter user '||username||' temporary tablespace temp;'
    from dba_users where temporary_tablespace='TEMP01' 
   drop  tablespace temp01 ;
  c.删除4g的logfile,如果是当前日志,需要切换日志;
      select * from v$logfile;
      alter system switch logfile;
      alter database drop logfile  group 5;
  d.重新开始归档,需要重新启动db.
  
8.重新编译失效对象
  a. 授权特殊对象:
     grant select on v_$session to public;
     grant select on dba_role_privs to public;
  b. 使用pl/sql编译失效的ZLHIS对象,有几个中文乱码的存储过程需要调整。
  c. 最后使用utlrp.sql脚本编译失效对象。ZLHIS中大量的私用同义词,在导入完成后,很多都是处于invalid状态,需要重新编译。oracle提供了$ORACLE_HOME/rdbms/admin/utlrp.sql脚本来编译数据库中的失效对象,最吸引我的是这个脚本的并行编译的能力,可极大的加快编译的速度。
       
9.断开老服务器的网络

10.修改小型机rac的public ip与vip,与老服务器相同,并重新启动监听。20分钟,由于是RAC环境,这一步操作比较麻烦,主要的命令是 
   srvctl modify nodeapps -n p710a -A  192.168.0.4/255.255.255.0/en0 
   详细步骤,请参考Metalink文档:276434.1 <Modifying the VIP or VIP Hostname of a 10g Oracle Clusterware Node>

11.应用测试,通知使用,迁移完成。

12.最后来提一个非常有用的expdp/impdp的命令。在导出/导入中,经常有可能某些原因,导致任务导常中止;这时候可以使用attach参数附加到先前的expdp/impdp作业中,expdp/impdp在作业中会创建一个用来记录作业状态的表,这个表就是作业可以继续的原因。作业名在在日志有记录,也可以通过查询dba_datapump_jobs来获得。attach的语法如下:
  ATTACH=[schema_name.]job_name
  Schema_name用于指定方案名,job_name用于指定导出作业名.注意,如果使用ATTACH选项,在命令行除了连接字符串和ATTACH选项外,不能指定任何其他选项,示例如下:
  Expdp system/oracle ATTACH=system.expdp_full_job

 

四 总结
   数据泵是个优秀的工具,特别是大数据的逻辑迁移,性能相比传统的exp/imp有质的提升,但传统的exp/imp还是有他的优势,最大的优势就是exp/imp不是服务器端工具,部署更为便利,且支持的版本更多。 整个迁移共计时间4.5小时,原来预计的7小时左右;由于导入时间大大优于估计时间,实际共消耗时间4.5小时,整个迁移过程非常顺利。如果是9i迁移到异构的平台,在使用exp/imp的情况下,除了表的数据以外,也可以手动实现部分并行操作,主要是索引与约束的创建。曾经在一个医院将190g的zlhis,也只用了4个小时的停机时间,完成了迁移,但整个过程比较复杂,可另行文描述。