传输表空间技术及字节序对跨平台迁移的影响

        传输表空间技术是数据迁移中非常重要的技术之一。它的作用是将一组自包含(Self-Contained),只读的表空间只导出元数据,然后在操作系统层面将表空间的数据文件直接复制到目标平台,再将元数据导入数据字典,即完迁移。  可以用来快速迁移表空间,也可以用来迁移整个库。

        Oracle用exp/imp或expdp/impdp来支持这个技术。

整理了三种情况:

一。 非跨平台的正常迁移流程。

二。不同字节序跨平台的表空间传输

三。相同字节序跨平台的表空间传输(有附上我自己写的更新数据文件头的c程序)


一。 首先来看非跨平台的正常迁移流程。   

1. 自包含检查

   connect / sysdba
   -- 非严格自包含检查,如对一些表索引不在同一表空间的也能通过检查
   exec dbms_tts.transport_set_check('DEMO_DATA',TRUE);
   -- 严格自包含检查
   exec dbms_tts.transport_set_check('DEMO_DATA',TRUE,TRUE);

  --显示检查结果
  SELECT * FROM transport_set_check('DEMO_DATA',TRUE);

  --如果检查没通过也没关系,Oracle可以多个表空间同时传输。
  exec dbms_tts.transport_set_check('DEMO_DATA,DEMO_IDX',TRUE,TRUE);
2. 传输步骤
  2.1 将表空间设为只读
    alter tablespace users read only;
  2.2 导出表空间
    exp '/ as sysdba' tablepacespaces=demo_data transport_tablespace=y file=exp_users.dmp;
  2.3 将表空间对应的数据文件转移到目标服务器上。
  2.4 导入表空间
    imp '/ as sysdba' tablespaces=demo_data transport_tablespace=y file=exp_demo.dmp datafiles='demo_data.dbf' ;
 至此,这个表空间就被包含在了新建的数据库中。

二。不同字节序跨平台的表空间传输
         由于不同平台的字节序不同,导入数据文件时,不同的字节序会导致数据不能被正确的读取。在做网络编程时,
  需要将传输数据转为网络字节序,再在接收端转回来本地字节序。  而 Oracle的数据文件在跨平台进行表空间传输时,同样也需要处理这个麻烦。

    Oracle目前支持一些跨平台的转换,能将文件格式转为目标服务器的字节序格式。
    可在下面SQL中查到支持哪些平台转换:

col PLATFORM_NAME for a40
    SELECT * FROM v$transportable_platform;
在数据库中查出当前或目标数据库当前的字节序信息:

col PLATFORM_NAME for a40
     SELECT d.platform_name,endian_format 
     FROM v$transportable_platform tp,v$database d
     WHERE tp.platform_name =d.platform_name;


 做个测试:
      将Oracle11gR2的一个表空间从Solaris(64bit)上转到Windows(64bit)上.
      Solaris 为大端方式(Big Endian)
      Windows 为小端方式(Little Endian)

  源平台导出部份:
   1. 建立一个表空间

create tablespace tbs_trans datafile '/u01/app/oracle/oradata/xcldb/tbs_trans_01.dbf' size 1m;
    create user usr_trans identified by 111111 default tablespace tbs_trans;
    grant connect,resource to usr_trans;
    connect usr_trans/111111;
    create table tb_trans as select rownum as seq from dual connect by rownum <= 10 ;
    select count(*) from tb_trans;
    disconnect;
    connect / as sysdba
    alter tablespace tbs_trans read only;
    exit;
2. 导出表空间

exp \'/ as sysdba\' tablespaces=tbs_trans transport_tablespace=y file=/u01/app/exp_tbs_trans.dmp 

 3. 通过RMAN将表空间数据文件转换出一个目标平台字节序相同格式的文件出来

rman target / nocatalog
    convert tablespace TBS_TRANS to platform 'Microsoft Windows x86 64-bit' format '/u01/app/%N_%f';
    exit;
    ls -lt /u01/app/TBS_TRANS* 
 4. 将导出的dmp文件(exp_tbs_trans.dmp)与转换后的数据文件(TBS_TRANS_5)都复制到目标平台上。
   
  目标平台导入部份
  5. 把传过来的,之前转换过的数据文件名字变得规范点

set oracle_sid=xcldb
    rman target / nocatalog
    report schema;
    convert datafile 'c:\tmp\TBS_TRANS_5' db_file_name_convert 'c:\tmp\TBS_TRANS_5','C:\ORACLE\ORADATA\XCLDB\TBS_TRANS_01.DBF';
 6. 创建相关用户

create user usr_trans identified by 111111 ;
    grant connect,resource to usr_trans;
 7.导入 
imp '/ as sysdba' tablespaces=tbs_trans transport_tablespace=y file=c:\tmp\exp_tbs_trans.dmp datafiles=C:\ORACLE\ORADATA\XCLDB\TBS_TRANS_01.DBF

 8.检查

 select name from v$datafile where name like '%TBS%' ;

 9. 此时两边tbs_trans表空间都为ReadOnly状态,记得将源平台与目标平台tbs_trans的表空间变更为可读写状态 

select tablespace_name,status from dba_tablespaces;
   alter tablespace tbs_trans read write ;
三。相同字节序跨平台的表空间传输
    上面是不同字节序的需要convert tablespace来转换格式,而如果是相同字节序的,是否能直接导出元数据后,再将数据文件复制过去就行了呢。
    比如: Windows与Linux都是小端方式 。
    Oracle10g以后,直接复制过去确实是可行的。整库复制过去都可以。
    10g以前的版本就要更改下数据文件头,让两边标识一样。否则imp时会识别不了。


  处理方法:
    1. 把数据文件头与文件内容分开。 
    2. 把数据文件复制过去,把A平台的数据文件头给抹了,把B平台的数据文件头给取出。
    3.  再将B的数据文件头与A的数据文件内容合并在一起,
就能识别了。

举个9i的例子
     1.  找出文件头大小. 以都有的user表空间数据文件查询即可出来。

Linux 平台:

select file_name,bytes from dba_data_files where tablespace_name='USERS';
        !ls -l  /u01/app/oracle/oradata/orcl2/users01.dbf

      SQL>  select file_name,bytes from dba_data_files where tablespace_name='USERS';

      FILE_NAME
      --------------------------------------------------------------------------------
           BYTES
      ----------
      /u01/app/oracle/oradata/orcl2/users01.dbf
         5242880

        SQL>  !ls -l  /u01/app/oracle/oradata/orcl2/users01.dbf
        -rw-r-----. 1 oracle oinstall 5251072 Feb 22 15:31 /u01/app/oracle/oradata/orcl2/users01.dbf

    SQL> select 5251072 - 5242880 from dual;

    5251072-5242880
    ---------------
               8192
 Windows 平台:

SQL>  select file_name,bytes from dba_data_files where tablespace_name='USERS';

FILE_NAME
--------------------------------------------------------------------------------
     BYTES
----------
C:\ORACLE\ORADATA\XCLDB\USERS01.DBF
   5242880


SQL> host dir  C:\ORACLE\ORADATA\XCLDB\USERS01.DBF
 驱动器 C 中的卷是 OS
 卷的序列号是 C8C0-48C4

 C:\ORACLE\ORADATA\XCLDB 的目录

2014/02/22  16:06         5,251,072 USERS01.DBF
               1 个文件      5,251,072 字节
               0 个目录 62,898,417,664 可用字节

SQL> select 5251072 - 5242880 from dual;

5251072-5242880
---------------
           8192
 8192 字节即为文件头大小. 两边都相同
 2. 更改文件头
   我自己写了个更新文件头的程序。UNIX/Linux下可以用dd命令。

/*************************************************
Author: xiongchuanliang
Description: 更新Oracle数据文件头
**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HEADESIZE 8192
#define MAXLEN 200

//将目标端的文件头提取出来
int getDestHeader(const char * fileName,unsigned char *fileHeader);
//用提取出来的文件头替换掉原来的文件头
int updateHeader(const char * fileName,unsigned char *fileHeader);

int main(void)
{
  char sourceFile[MAXLEN] = {0};
  char headerFile[MAXLEN] = {0};

  printf("跨平台表空间传输\n");
  printf("同字节序文件的跨平台测试(10g以下)\n");

  //"C:\\tmp\\lx\\tbs_trans_01.dbf1"
  printf("将从源数据库传到本地临时目录的数据文件路径。\n");
  printf("输入源平台数据文件如(C:\\tmp\\lx\\tbs_trans_01.dbf):\n");
    scanf ("%199s",sourceFile);

  //C:\oracle\oradata\xcldb\USERS01.DBF1
  printf("从本地数据文件中任选一个取出文件头,替换源平台原有的文件头。\n");
  printf("输入本地数据文件(如C:\\oracle\\oradata\\xcldb\\USERS01.DBF):\n");
    scanf ("%199s",headerFile);

  unsigned char destHeader[HEADESIZE] = {0};

  if( getDestHeader(headerFile,destHeader) == 0)
  {
    updateHeader(sourceFile,destHeader);
  }
  return 0;
}

//将目标端的文件头提取出来
int getDestHeader(const char * fileName,unsigned char *fileHeader)
{
  if(fileName == NULL) return -1;

  //将目标端的文件头提取出来
  FILE * fpDest = fopen(fileName,"rb");
  if(fpDest== NULL )
  {
    printf("文件(%s)打开失败!\n",fileName);     
    return -1;
  }
  fseek(fpDest,0L,SEEK_SET);        
  size_t readbyte = fread(fileHeader,1, HEADESIZE,fpDest);
  if( readbyte <= 0 )
  {
    printf("文件头读取失败!\n"); 
    fclose(fpDest);
    return -1;
  }else if(readbyte != HEADESIZE){
    printf("读取出的文件头长度(%d)不够,此事必有蹊跷! 请重新检查。\n",readbyte);  
    fclose(fpDest);
    return -1;
  }
  printf("文件头大小:%d\n",readbyte);  
  fclose(fpDest);
  return 0;
}

//用提取出来的文件头替换掉原来的文件头
int updateHeader(const char * fileName,unsigned char *fileHeader)
{
  FILE * fpSource = fopen(fileName,"rb+");
  if(fpSource == NULL )
  {
    printf("文件(%s)打开失败!\n",fileName);     
    return -1;
  }
  fseek(fpSource,0L,SEEK_SET);
  size_t writebyte = fwrite(fileHeader,sizeof(fileHeader),1,fpSource);
  if( writebyte <= 0 )
  {
    printf("文件头写入失败!\n");     
  }else{
    printf("已替换到文件%s上.\n",fileName);    
    printf("文件头替换工作顺利完成!\n");
  } 
  fclose(fpSource);
  return 0;
}
   编译运行程序,输入相关的文件合路径,执行,就能将数据文件头更新成本地的信息了,

    至此,imp时就不会报错了。
3. 其它命令和流程与上面的"非跨平台的正常迁移流程"是一样的,关键点就是文件头处理部份不同。


附11gR2支持的平台列表:

SQL>  col PLATFORM_NAME for a40
    SELECT * FROM v$transportable_platform;SQL> 

PLATFORM_ID PLATFORM_NAME                            ENDIAN_FORMAT
----------- ---------------------------------------- --------------
          1 Solaris[tm] OE (32-bit)                  Big
          2 Solaris[tm] OE (64-bit)                  Big
          7 Microsoft Windows IA (32-bit)            Little
         10 Linux IA (32-bit)                        Little
          6 AIX-Based Systems (64-bit)               Big
          3 HP-UX (64-bit)                           Big
          5 HP Tru64 UNIX                            Little
          4 HP-UX IA (64-bit)                        Big
         11 Linux IA (64-bit)                        Little
         15 HP Open VMS                              Little
          8 Microsoft Windows IA (64-bit)            Little

PLATFORM_ID PLATFORM_NAME                            ENDIAN_FORMAT
----------- ---------------------------------------- --------------
          9 IBM zSeries Based Linux                  Big
         13 Linux x86 64-bit                         Little
         16 Apple Mac OS                             Big
         12 Microsoft Windows x86 64-bit             Little
         17 Solaris Operating System (x86)           Little
         18 IBM Power Based Linux                    Big
         19 HP IA Open VMS                           Little
         20 Solaris Operating System (x86-64)        Little
         21 Apple Mac OS (x86-64)                    Little

20 rows selected.

另个关于字节序对网络编程的影响可以看看这篇<<网络编程(7)字节序对跨平台数据传输的影响>>


MAIL: xcl_168@aliyun.com

BLOG: http://blog.csdn.net/xcl168






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值