跨平台表空间传输(摘自eygle《循序渐进Oracle》)
需要注意的是,在Oracle 10g之前,数据文件是不能够跨平台传输使用的,从Oracle 10g开始,Oracle支持跨平台的表空间传输,这极大地增强了数据迁移的便利性。
1. 字节顺序和平台
数据文件所以不能跨平台,主要是由于不同平台的字节顺序不同,这是计算机领域由来已久的问题之一,在各种计算机体系结构中,由于对于字、字节等的存储机制有所不同,通信双方交流的信息单元(比特、字节、字、双字等)应该以什么样的顺序进行传送就成了一个问题,如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。
目前在各种体系的计算机中通常采用的字节存储机制主要有两种:Big-Endian和Little-Endian 。
一些操作系统(包括Windows)在低位内存地址中存放二进制数据的最低有效字节,因此这种系统被称为Little Endian;一些操作系统(包括Solaris)将最高有效字节存储在低位内存地址中,因此这种系统被称为Big Endian。
举一个简单点的例子,假如1122这样一个数据要存入不同系统,对于Little Endian的系统,存储的顺序就是2211,小头在前;而对于Big Endian的系统来说,存储顺序就是1122,大头在前,显然Big Endian更符合我们通常的语言习惯。
那么跨平台的问题就出现了,当一个Little Endian的系统试图从一个Big Endian的系统中读取数据时,就需要通过转换,否则不同的字节顺序将导致数据不能被正确读取。
说明:据考证,Endian这个词来源于Jonathan Swift在1726年写的讽刺小说《Gulliver's Travels》(《格利佛游记》)。该小说在描述Gulliver畅游小人国时碰到了如下的一个场景。在小人国里的小人因为非常小(身高6英寸)所以总是碰到一些意想不到的问题。有一次因为对水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开的争论而引发了一场战争,并形成了两支截然对立的队伍:支持从Big-End剥开的人Swift就称作Big-Endians,而支持从Little-End剥开的人就称作Little-Endians(后缀ian表明的就是支持某种观点的人)。Endian这个词由此而来。
清楚了这个问题,接下来就可以来看看Oracle是如何处理这种情况的。
2. 源平台和目标平台
首先在迁移之前,需要确认一下源平台和目标平台的平台信息,这些信息可以通过视图v$transportable_platform和v$database视图联合查询得到。以下是源平台的信息:
SQL> col PLATFORM_NAME for a30
SQL> SELECT d.platform_name, endian_format
2 FROM v$transportable_platform tp, v$database d
3 WHERE tp.platform_name = d.platform_name;
PLATFORM_NAME ENDIAN_FORMAT
------------------------------ --------------
Solaris[tm] OE (64-bit) Big
查询目标数据库平台信息:
SQL> col platform_name for a40
SQL> SELECT d.platform_name, endian_format
2 FROM v$transportable_platform tp, v$database d
3 WHERE tp.platform_name = d.platform_name;
PLATFORM_NAME ENDIAN_FORMAT
---------------------------------------- --------------
Microsoft Windows IA (32-bit) Little
看到Windows平台和Solaris平台的字节顺序是不同的,Windows是Little-Endian,而Solaris是Big-Endian的。可以通过数据库查询Oracle 10g支持的平台转换:
SQL> col PLATFORM_NAME for a40
SQL> select * from v$transportable_platform;
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
9 IBM zSeries Based Linux Big
13 Linux 64-bit for AMD Little
16 Apple Mac OS Big
12 Microsoft Windows 64-bit for AMD Little
17 Solaris Operating System (x86) Little
18 IBM Power Based Linux Big
17 rows selected.
3. 源平台的导出及转换
接下来开始我们的测试,创建一个独立的自包含表空间,并创建一个测试表:
SQL> select name from v$datafile;
NAME
--------------------------------------------------------------------------------
/data2/ora10g/oradata/mars/system01.dbf
/data2/ora10g/oradata/mars/undotbs01.dbf
/data2/ora10g/oradata/mars/sysaux01.dbf
/data2/ora10g/oradata/mars/users01.dbf
SQL> create tablespace trans
2 datafile '/data2/ora10g/oradata/mars/trans.dbf' size 10M;
Tablespace created.
SQL> create user trans identified by trans
2 default tablespace trans;
User created.
SQL> grant connect,resource to trans;
Grant succeeded.
SQL> connect trans/trans
Connected.
SQL> create table test as select * from dict;
Table created.
SQL> select count(*) from test;
COUNT(*)
----------
617
将表空间设置为只读:
SQL> connect / as sysdba
Connected.
SQL> alter tablespace trans read only;
Tablespace altered.
导出要传输的表空间:
$ exp "'/ as sysdba"' tablespaces=trans transport_tablespace=y file=exp_trans.dmp
Export: Release 10.2.0.1.0 - Production on Thu Mar 22 16:31:15 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
Note: table data (rows) will not be exported
About to export transportable tablespace metadata...
For tablespace TRANS ...
. exporting cluster definitions
. exporting table definitions
. . exporting table TEST
. exporting referential integrity constraints
. exporting triggers
. end transportable tablespace metadata export
Export terminated successfully without warnings.
使用RMAN转换文件格式:
$ rman target /
Recovery Manager: Release 10.2.0.1.0 - Production on Thu Mar 22 16:34:30 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
connected to target database: MARS (DBID=1034439893)
RMAN> convert tablespace trans
2> to platform 'Microsoft Windows IA (32-bit)'
3> format '/tmp/%N_%f';
Starting backup at 22-MAR-07
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=140 devtype=DISK
channel ORA_DISK_1: starting datafile conversion
input datafile fno=00005 name=/data2/ora10g/oradata/mars/trans.dbf
converted datafile=/tmp/TRANS_5
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:01
Finished backup at 22-MAR-07
确认导出文件已生成:
$ ls -l /tmp/TRANS*
-rw-r----- 1 oracle dba 10493952 Mar 22 16:37 /tmp/TRANS_5
3. 文件传输
通过FTP获得两个文件,注意应该使用二进制方式传输(bin模式):
D:"oradata"EYGLE"DATAFILE>ftp 172.16.33.50
Connected to 172.16.33.50.
220 testdbserver.hurray.com.cn FTP server (SunOS 5.8) ready.
User (172.16.33.50:(none)): gqgai
331 Password required for gqgai.
Password:
230 User gqgai logged in.
ftp> bin
200 Type set to I.
ftp> mget /export/home/oracle/exp_trans.dmp
200 Type set to I.
mget /export/home/oracle/exp_trans.dmp? y
200 PORT command successful.
150 Binary data connection for /export/home/oracle/exp_trans.dmp (172.16.34.89,5006) (3072 bytes).
226 Binary Transfer complete.
ftp: 收到 3072 字节,用时 0.00Seconds 3072000.00Kbytes/sec.
ftp> mget /tmp/TRANS_5
200 Type set to I.
mget /tmp/TRANS_5? y
200 PORT command successful.
150 Binary data connection for /tmp/TRANS_5 (172.16.34.89,5008) (10493952 bytes).
226 Binary Transfer complete.
ftp: 收到 10493952 字节,用时 1.13Seconds 9270.28Kbytes/sec.
4. 目标数据库的导入
在目标数据库中,也可以使用RMAN对备份文件进行转换,以使数据文件具有更规范的名称:
D:"oradata"EYGLE"DATAFILE>rman target /
恢复管理器: Release 10.2.0.1.0 - Production on 星期四 3月 22 17:18:50 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到目标数据库: EYGLE (DBID=1417824532)
RMAN> convert datafile 'D:"oradata"EYGLE"DATAFILE"TRANS_5'
2> db_file_name_convert
3> 'D:"oradata"EYGLE"DATAFILE"TRANS_5','D:"oradata"EYGLE"DATAFILE"TRANS01.DBF';
启动 backup 于 22-3月 -07
使用目标数据库控制文件替代恢复目录
分配的通道: ORA_DISK_1
通道 ORA_DISK_1: sid=144 devtype=DISK
通道 ORA_DISK_1: 启动数据文件转换
输出文件名=D:"ORADATA"EYGLE"DATAFILE"TRANS_5
已转换的数据文件 = D:"ORADATA"EYGLE"DATAFILE"TRANS01.DBF
通道 ORA_DISK_1: 数据文件转换完毕, 经过时间: 00:00:08
完成 backup 于 22-3月 -07
然后需要在目标数据库创建相应的用户:
SQL> create user trans identified by trans;
用户已创建。
SQL> grant connect,resource to trans;
授权成功。
接下来可以执行导入:
D:"oradata"EYGLE"DATAFILE>imp '/ as sysdba' tablespaces=trans transport_tablespace=y file=exp_trans.dmp datafiles=D:"oradata"EYGLE"DATAFILE"TRANS01.DBF
Import: Release 10.2.0.1.0 - Production on 星期四 3月 22 17:34:27 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V10.02.01 创建的导出文件
即将导入可传输的表空间元数据...
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 SYS 的对象导入到 SYS
. 正在将 SYS 的对象导入到 SYS
. 正在将 TRANS 的对象导入到 TRANS
. . 正在导入表 "TEST"
. 正在将 SYS 的对象导入到 SYS
成功终止导入, 没有出现警告。
注意:此处也可以在IMP时通过fromuser/touser参数将数据导入其他用户下。
现在这个表空间已经被插入到新的数据库中,并且数据全部传输过来:
SQL> select name from v$datafile;
NAME
------------------------------------------------------------
D:"ORADATA"EYGLE"DATAFILE"O1_MF_SYSTEM_2G8OHFX6_.DBF
D:"ORADATA"EYGLE"DATAFILE"O1_MF_UNDOTBS1_2G8OJ6NB_.DBF
D:"ORADATA"EYGLE"DATAFILE"O1_MF_SYSAUX_2G8OJHP9_.DBF
D:"ORADATA"EYGLE"DATAFILE"O1_MF_USERS_2G8OJYYS_.DBF
D:"ORADATA"EYGLE"DATAFILE"O1_MF_EYGLE_2YDGSVH7_.DBF
D:"ORADATA"EYGLE"DATAFILE"TRANS01.DBF
已选择6行。
SQL> select count(*) from trans.test;
COUNT(*)
----------
617
导入后的表空间还处于read only状态,确认后可以更改为读写模式:
SQL> select tablespace_name,status from dba_tablespaces;
TABLESPACE_NAME STATUS
------------------------------ ---------
SYSTEM ONLINE
UNDOTBS1 ONLINE
SYSAUX ONLINE
TEMP ONLINE
USERS ONLINE
EYGLE ONLINE
TRANS READ ONLY
已选择7行。
SQL> alter tablespace trans read write;
表空间已更改。
同样,传输表空间也可以通过数据泵来完成,以下是Oracle 10gR1中插入表空间的简单示例:
E:"Oracle"oradata"eygle"dpdata>impdp eygle/eygle dumpfile=trans.dmp directory=dpdata transport_datafiles='E:"Oracle"oradata"eygle"EYGLE"DATAFILE"TRANS01.DBF'
Import: Release 10.1.0.2.0 - Production on 星期二, 27 4月, 2004 15:03
Copyright (c) 2003, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production
With the Partitioning, OLAP and Data Mining options
已成功加载/卸载了主表 "EYGLE"."SYS_IMPORT_TRANSPORTABLE_01"
启动 "EYGLE"."SYS_IMPORT_TRANSPORTABLE_01": eygle/******** dumpfile=trans.dmp directory=dpdata transport_datafiles='E:"
Oracle"oradata"eygle"EYGLE"DATAFILE"TRANS01.DBF'
处理对象类型 TRANSPORTABLE_EXPORT/PLUGTS_BLK
处理对象类型 TRANSPORTABLE_EXPORT/TABLE
处理对象类型 TRANSPORTABLE_EXPORT/TTE_POSTINST/PLUGTS_BLK
作业 "EYGLE"."SYS_IMPORT_TRANSPORTABLE_01" 已于 15:03 成功完成
5. 同字节序文件的跨平台
前面说过,当一个Little Endian的系统试图从一个Big Endian的系统中读取数据时,就需要通过转换,否则不同的字节顺序将导致数据不能被正确读取。那么另外一个问题出现了,如果字节序相同的平台进行文件交互,数据能否被正确读取呢?
理论上的确是可以的,但是由于在不同的平台上操作系统会在数据文件头写上系统信息,这部分信息无法跨越平台,所以仍然会导致跨平台的文件无法被数据库正确识别(Oracle 10g中同字节序平台数据文件头不再存在跨平台的迁移问题)。
接下来通过Windows和Linux平台来进行一个跨平台测试。相信通过这个测试可以对以上提出的问题做出一个很好的回答。
其中一个实验环境为Windows XP + Oracle10g 10.2.0.1,具体如下:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 – Production
另一个实验环境为Red Hat Enterprise Linux AS release 3 + Oracle 9iR2 9.2.0.4,具体如下:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Linux: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production
看一下Linux平台,文件头被操作系统保留了8192字节:
SQL> select file_name,bytes from dba_data_files
2 where tablespace_name='USERS';
FILE_NAME BYTES
----------------------------------- ----------
/opt/oracle/oradata/eygle/users.dbf 10485760
SQL> !
[oracle@jumper eygle]$ ll users.dbf
-rw-r----- 1 oracle dba 10493952 Mar 23 10:14 users.dbf
[oracle@jumper eygle]$ exit
exit
SQL> select 10493952 -10485760 diff from dual;
DIFF
----------
8192
Windows平台上数据文件头同样保留了8192字节:
SQL> select file_name,bytes from dba_data_files
2 where tablespace_name='USERS';
FILE_NAME BYTES
--------------------------------------------------- ----------
D:"ORADATA"EYGLE"DATAFILE"O1_MF_USERS_2G8OJYYS_.DBF 5242880
SQL> host dir D:"ORADATA"EYGLE"DATAFILE"O1_MF_USERS_2G8OJYYS_.DBF
驱动器 D 中的卷是 PRIVAT
卷的序列号是 94B0-FD3B
D:"ORADATA"EYGLE"DATAFILE 的目录
2007-03-22 17:41 5,251,072 O1_MF_USERS_2G8OJYYS_.DBF
1 个文件 5,251,072 字节
0 个目录 1,635,913,728 可用字节
SQL> select 5251072 -5242880 diff from dual;
DIFF
----------
8192
可以通过Linux和Windows平台来进行一个小测试实验,这两个平台都是Little Endian的系统:
SQL> select * from v$transportable_platform;
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
…………
17 rows selected.
首先在Linux下Oracle 9204中创建一个测试表空间:
[oracle@jumper oracle]$ cd oradata/eygle
[oracle@jumper eygle]$ sqlplus "/ as sysdba"
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning option
JServer Release 9.2.0.4.0 - Production
SQL> create tablespace eyglee datafile size 10M;
Tablespace created.
创建测试用户并创建一个测试表:
SQL> create user eyglee identified by eyglee default tablespace eyglee;
User created.
SQL> grant connect,resource to eyglee;
Grant succeeded.
SQL> connect eyglee/eyglee
Connected.
SQL> create table eyglee as select * from dict;
Table created.
SQL> select count(*) from eyglee;
COUNT(*)
----------
477
将表空间设置为只读:
SQL> connect / as sysdba
Connected.
SQL> alter tablespace eyglee read only;
Tablespace altered.
SQL> select file_name from dba_data_files where tablespace_name='EYGLEE';
FILE_NAME
------------------------------------------------------------
/opt/oracle/oradata/eygle/o1_mf_eyglee_309yc9gr_.dbf
压缩文件以方便传输:
[oracle@jumper eygle]$ tar -cvf eyglee.tar o1_mf_eyglee_309yc9gr_.dbf
o1_mf_eyglee_309yc9gr_.dbf
[oracle@jumper eygle]$ gzip eyglee.tar
导出表空间:
[oracle@jumper eygle]$ exp "'/ as sysdba"' tablespaces=eyglee transport_tablespace=y file=trans_eyglee.dmp
Export: Release 9.2.0.4.0 - Production on Sat Mar 24 18:17:32 2007
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning option
JServer Release 9.2.0.4.0 - Production
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
Note: table data (rows) will not be exported
About to export transportable tablespace metadata...
For tablespace EYGLEE ...
. exporting cluster definitions
. exporting table definitions
. . exporting table EYGLEE
. exporting referential integrity constraints
. exporting triggers
. end transportable tablespace metadata export
Export terminated successfully without warnings.
[oracle@jumper eygle]$ ll *eyglee*
-rw-r--r-- 1 oracle dba 32985 Mar 24 18:14 eyglee.tar.gz
-rw-r----- 1 oracle dba 10493952 Mar 24 18:13 o1_mf_eyglee_309yc9gr_.dbf
-rw-r--r-- 1 oracle dba 16384 Mar 24 18:17 trans_eyglee.dmp
传输文件到Windows平台:
D:"oradata"EYGLE"DATAFILE>dir *eyglee*
D:"oradata"EYGLE"DATAFILE 的目录
2007-03-24 18:21 32,985 eyglee.tar.gz
2007-03-24 18:21 16,384 trans_eyglee.dmp
D:"oradata"EYGLE"DATAFILE>gzip -d eyglee.tar.gz
D:"oradata"EYGLE"DATAFILE>tar -xvf eyglee.tar
tar: blocksize = 20
x o1_mf_eyglee_309yc9gr_.dbf, 10493952 bytes, 20496 tape blocks
在Windows上创建新用户:
SQL> create user eyglee identified by eyglee;
用户已创建。
SQL> grant connect ,resource to eyglee;
授权成功。
如果此时导入会出现ORA-00600错误:
D:"oradata"EYGLE"DATAFILE>imp '/ as sysdba' tablespaces=eyglee transport_tablespace=y file=trans_eyglee.dmp datafiles=d:"oradata"EYGLE"DATAFILE"o1_mf_eyglee_309yc9gr_.dbf
Import: Release 10.2.0.1.0 - Production on 星期六 3月 24 18:59:23 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V09.02.00 创建的导出文件
即将导入可传输的表空间元数据...
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 SYS 的对象导入到 SYS
. 正在将 SYS 的对象导入到 SYS
IMP-00017: 由于 ORACLE 错误 600, 以下语句失败:
"BEGIN sys.dbms_plugts.beginImpTablespace('EYGLEE',9,'SYS',1,0,8192,1,1899"
"6106462,1,2147483645,8,128,8,0,1,0,8,1407686520,1,1,18996106397,NULL,0,0,NU"
"LL,NULL); END;"
IMP-00003: 遇到 ORACLE 错误 600
ORA-00600: 内部错误代码, 参数: [krhcvt_filhdr_v10_01], [], [], [], [], [], [], []
ORA-06512: 在 "SYS.DBMS_PLUGTS", line 1801
ORA-06512: 在 line 1
IMP-00000: 未成功终止导入
其中“参数: [krhcvt_filhdr_v10_01]”提示指文件头无法正确识别。可以通过对这个文件进行一个特殊操作,为文件更换一个Windows下数据文件的文件头,则数据文件就应该能够被数据库识别。
以下是这个“小手术”操作的过程。首先提取一个Windows数据文件头:
D:"oradata"EYGLE"DATAFILE>dd if=O1_MF_USERS_2G8OJYYS_.DBF of=header.dbf bs=8192 count=1
1+0 records in
1+0 records out
然后去除Linux下的数据文件头:
D:"oradata"EYGLE"DATAFILE>dd if=o1_mf_eyglee_309yc9gr_.dbf of=eyglee.dbf bs=8192 skip=1
1280+0 records in
1280+0 records out
最后将这两个文件合二为一:
D:"oradata"EYGLE"DATAFILE>copy /b header.dbf+eyglee.dbf eygleee.dbf
header.dbf
eyglee.dbf
已复制 1 个文件。
现在拥有的新文件eygleee.dbf就具有了一个Windows平台的文件头以及Linux下的“文件身”。至此这个文件就能够被Windows上的Oracle识别了,可以执行导入操作:
D:"oradata"EYGLE"DATAFILE>imp '/ as sysdba' tablespaces=eyglee transport_tablespace=y file=trans_eyglee.dmp datafiles=d:"oradata"EYGLE"DATAFILE"eygleee.dbf
Import: Release 10.2.0.1.0 - Production on 星期六 3月 24 19:22:13 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V09.02.00 创建的导出文件
即将导入可传输的表空间元数据...
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 SYS 的对象导入到 SYS
. 正在将 SYS 的对象导入到 SYS
. 正在将 EYGLEE 的对象导入到 EYGLEE
. . 正在导入表 "EYGLEE"
成功终止导入, 没有出现警告。
此时数据已经能够被正确识别:
SQL> connect eyglee/eyglee
已连接。
SQL> select count(*) from eyglee;
COUNT(*)
----------
477
最后将表空间更改为读写模式,可以进行正常的数据操作:
SQL> connect / as sysdba
已连接。
SQL> alter tablespace eyglee read write;
表空间已更改。
SQL> connect eyglee/eyglee
已连接。
SQL> insert into eyglee select * from eyglee;
已创建477行。
SQL> insert into eyglee select * from eyglee;
已创建954行。
SQL> insert into eyglee select * from eyglee;
已创建1908行。
SQL> commit;
提交完成。
SQL> select count(*) from eyglee;
COUNT(*)
----------
3816
通过这个实验,还可以得出另外一个结论,Oracle 9i的数据文件可以通过表空间传输迁移到Oracle 10g中使用。
6. Oracle 10g同字节序跨平台迁移的增强
上一节介绍的方法不免过于复杂,也许很多朋友会发出这样的疑问,既然同字节序数据文件跨平台的差异如此之小,为什么Oracle不直接实现这一技术呢?
也许是这一迁移的技术优先级较低,在Oracle10gR2中,Oracle开始支持同字节序数据库的跨平台迁移。
这一技术实现有以下几点注意事项:
¡ 源平台和目的平台需要具有相同的字节序
¡ 重做日志文件和控制文件不会传输,迁移之后需要重建控制文件使用RESETLOGS方式打开数据库;
¡ 临时文件不会被传输;
¡ BFILES、外部表和Directories、口令文件等不会被传输。
下面通过Linux平台到Windows平台的迁移来看一下这一技术的实现。
(1)确认平台及版本。首先要确定源平台和目标平台具有相同的字节序:
SQL> select PLATFORM_NAME, ENDIAN_FORMAT from V$TRANSPORTABLE_PLATFORM
2 where platform_name in ('Linux IA (32-bit)','Microsoft Windows IA (32-bit)');
PLATFORM_NAME ENDIAN_FORMAT
---------------------------------------- --------------
Microsoft Windows IA (32-bit) Little
Linux IA (32-bit) Little
然后需要确定源平台及目标平台的数据库版本,通常需要这两者具有相同的数据库版本,本例的情况有所不同,Linux平台的数据库版本为10.2.0.1,Windows平台的数据库版本为10.2.0.3,数据库版本不同将使情况稍微复杂一点,而且需要注意的是,通常高版本的数据库不能向低版本迁移。
(2)确认迁移是否支持。跨平台迁移需要数据库处于READ ONLY模式打开,使用DBMS_TDB.CHECK_DB进行检查:
SQL> set serveroutput on
SQL> declare
2 db_ready boolean;
3 begin
4 db_ready := dbms_tdb.check_db('Microsoft Windows IA (32-bit)');
5 end;
6 /
PL/SQL procedure successfully completed.
如果以上过程成功执行,并没有其他相关警告输出,则说明数据库可以支持跨平台转移。
(3)检查外部对象。使用DBMS_TDB.CHECK_EXTERNAL来识别外部表、Directories或BFILES等,这些对象所指向的外部数据不能被RMAN自动转移。
SQL> set serveroutput on
SQL> declare
2 external boolean;
3 begin
4 external := dbms_tdb.check_external;
5 end;
6 /
The following directories exist in the database:
SYS.DATA_PUMP_DIR
PL/SQL procedure successfully completed.
如果数据库中存在外部表、DIRECTORIES等,则以上过程执行后的输出与以上类似。
(4)使用RMAN进行跨平台文件迁移。执行跨平台迁移首先要通过RMAN对数据文件进行转换,RMAN执行过程如下:
[oracle@danaly eygle]$ rman target /
Recovery Manager: Release 10.2.0.1.0 - Production on Sat Jun 23 23:06:52 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
connected to target database: EYGLE (DBID=1445136501)
RMAN> CONVERT DATABASE NEW DATABASE 'JULIA'
2> TRANSPORT SCRIPT '/opt/oracle/oradata/transport/transport.sql'
3> TO PLATFORM 'Microsoft Windows IA (32-bit)'
4> DB_FILE_NAME_CONVERT '/opt/oracle/oradata/eygle/EYGLE/datafile' '/opt/oracle/oradata/transport';
Starting convert at 23-JUN-07
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=159 devtype=DISK
Directory SYS.DATA_PUMP_DIR found in the database
User SYS with SYSDBA and SYSOPER privilege found in password file
channel ORA_DISK_1: starting datafile conversion
input datafile
fno=00001 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_system_37tc1xns_.dbf
converted datafile=/opt/oracle/oradata/transport/o1_mf_system_37tc1xns_.dbf
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:15
channel ORA_DISK_1: starting datafile conversion
input datafile
fno=00002 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_undotbs1_37tc29mb_.dbf
converted datafile=/opt/oracle/oradata/transport/o1_mf_undotbs1_37tc29mb_.dbf
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:07
channel ORA_DISK_1: starting datafile conversion
input datafile
fno=00003 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_sysaux_37tc2gqc_.dbf
converted datafile=/opt/oracle/oradata/transport/o1_mf_sysaux_37tc2gqc_.dbf
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:07
channel ORA_DISK_1: starting datafile conversion
input datafile
fno=00004 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_users_37tc2tth_.dbf
converted datafile=/opt/oracle/oradata/transport/o1_mf_users_37tc2tth_.dbf
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:01
Run SQL script /opt/oracle/oradata/transport/transport.sql on the target platform to create database
Edit init.ora file /opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora. This PFILE will be used to create the database on the target platform
To recompile all PL/SQL modules, run utlirp.sql and utlrp.sql on the target platform
To change the internal database identifier, use DBNEWID Utility
Finished backup at 23-JUN-07
RMAN的转换语句中指定生成一个转换脚本transport.sql用于参考,转换的目标平台是Microsoft Windows IA (32-bit),所有的数据文件转换后存放在一个新的目录下。
最后RMAN还自动生成一个参数文件,这个文件是init_00il1i4r_1_0.ora,这个参数文件里包含了一些重要的初始化参数,可以根据需要进行相应的更改,由于平台以及路径的不同,很多涉及路径的参数都需要进行变更,这个参数文件的内容大致分为3个部分。
第1部分列出需要修改的参数:
# Please change the values of the following parameters:
control_files = "/opt/oracle/product/10.2.0/dbs/cf_D-JULIA_id-1445136501_00il1i4r"
db_create_file_dest = "/opt/oracle/product/10.2.0/dbs/eygle"
db_recovery_file_dest = "/opt/oracle/product/10.2.0/dbs/flash_recovery_area"
db_recovery_file_dest_size= 2147483648
background_dump_dest = "/opt/oracle/product/10.2.0/dbs/bdump"
user_dump_dest = "/opt/oracle/product/10.2.0/dbs/udump"
core_dump_dest = "/opt/oracle/product/10.2.0/dbs/cdump"
audit_file_dest = "/opt/oracle/product/10.2.0/dbs/adump"
db_name = "JULIA"
第2部分列出了建议Review的参数:
# Please review the values of the following parameters:
remote_login_passwordfile= "EXCLUSIVE"
db_domain = ""
dispatchers = "(PROTOCOL=TCP) (SERVICE=eygleXDB)"
第3部分列出了来自于源数据库的一些特殊设置,这些参数可以酌情修改:
# The values of the following parameters are from source database:
processes = 150
sga_target = 943718400
db_block_size = 8192
compatible = "10.2.0.1.0"
db_file_multiblock_read_count= 16
undo_management = "AUTO"
undo_tablespace = "UNDOTBS1"
job_queue_processes = 10
open_cursors = 300
pga_aggregate_target = 314572800
参数文件的内容可以在新的平台上重新创建,这个参数文件可以作为参考。
(5)转移文件到目标平台。源平台的工作完成之后,数据文件可以通过FTP等方式转移到目标平台,部署到相应目录,我的操作步骤如下:
C:"oracle"oradata>gzip -d trans.tar.gz
C:"oracle"oradata>tar -xvf trans.tar
tar: blocksize = 20
x transport/transport.sql, 2397 bytes, 5 tape blocks
x transport/o1_mf_sysaux_37tc2gqc_.dbf, 125837312 bytes, 245776 tape blocks
x transport/o1_mf_undotbs1_37tc29mb_.dbf, 209723392 bytes, 409616 tape blocks
x transport/o1_mf_system_37tc1xns_.dbf, 314580992 bytes, 614416 tape blocks
x transport/o1_mf_users_37tc2tth_.dbf, 5251072 bytes, 10256 tape blocks
C:"oracle"oradata>mkdir -p JULIA"DATAFILE
C:"oracle"oradata>mkdir JULIA"CONTROLFILE
C:"oracle"oradata>mkdir JULIA"ONLINELOG
C:"oracle"oradata>mv transport"* JULIA"DATAFILE
(6)创建基础环境。首先创建相关目录:
C:"oracle"oradata>mkdir C:"oracle"admin"julia"adump
C:"oracle"oradata>mkdir C:"oracle"admin"julia"bdump
C:"oracle"oradata>mkdir C:"oracle"admin"julia"cdump
C:"oracle"oradata>mkdir C:"oracle"admin"julia"dpdump
C:"oracle"oradata>mkdir C:"oracle"admin"julia"pfile
C:"oracle"oradata>mkdir C:"oracle"admin"julia"udump
创建Windows数据库服务:
C:"oracle"oradata>oradim -new -sid julia
实例已创建。
修改参数文件,参数文件可以从前面自动生成的参数文件进行修改得到,其中目录结构需要依据新平台的具体设置进行修改,和存储主要相关的两个参数修改如下:
db_create_file_dest = "C:"oracle"oradata"
db_recovery_file_dest = "C:"oracle"flash_recovery_area"
修改后的参数文件在Windows上应该位于$ORACLE_HOME/database下。参数文件中的另外一个重要参数是控制文件路径:
control_files = "/opt/oracle/product/10.2.0/dbs/cf_D-JULIA_id-1445136501_00il1i4r"
如果计划使用OMF管理,可以暂时注释这一参数,在创建控制文件后再将控制文件的名称路径追加到参数文件中。
(7)迁移步骤。准备工作完成之后,就可以进行新平台的数据库加载等工作,这些工作还可以参考在源平台生成的transport.sql脚本。
这个脚本的第一部分给出了使用参数文件启动实例及重新创建控制文件的语法参考,当然还需要修改才能使用这段脚本:
STARTUP NOMOUNT PFILE='/opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora'
CREATE CONTROLFILE REUSE SET DATABASE "LINDB10G" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 292
LOGFILE
GROUP 1 SIZE 50M,
GROUP 2 SIZE 50M,
GROUP 3 SIZE 50M
DATAFILE
'/opt/oracle/oradata/transport/o1_mf_system_37tc1xns_.dbf',
'/opt/oracle/oradata/transport/o1_mf_undotbs1_37tc29mb_.dbf',
'/opt/oracle/oradata/transport/o1_mf_sysaux_37tc2gqc_.dbf',
'/opt/oracle/oradata/transport/o1_mf_users_37tc2tth_.dbf'
CHARACTER SET ZHS16GBK
;
由于已经编辑好了新的参数文件,所以可以使用这个参数文件启动实例:
C:"oracle"oradata>set ORACLE_SID=julia
C:"oracle"oradata>sqlplus "/ as sysdba"
SQL*Plus: Release 10.2.0.3.0 - Production on 星期一 6月 25 09:45:59 2007
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
已连接到空闲例程。
SQL> startup nomount pfile=?"database"initjulia.ora
ORACLE 例程已经启动。
Total System Global Area 943718400 bytes
Fixed Size 1293960 bytes
Variable Size 239075704 bytes
Database Buffers 700448768 bytes
Redo Buffers 2899968 bytes
接下来创建控制文件:
SQL> CREATE CONTROLFILE REUSE SET DATABASE "JULIA" RESETLOGS NOARCHIVELOG
2 MAXLOGFILES 16
3 MAXLOGMEMBERS 3
4 MAXDATAFILES 100
5 MAXINSTANCES 8
6 MAXLOGHISTORY 292
7 LOGFILE
8 GROUP 1 SIZE 10M,
9 GROUP 2 SIZE 10M,
10 GROUP 3 SIZE 10M
11 DATAFILE
12 'C:"oracle"oradata"JULIA"DATAFILE"o1_mf_system_37tc1xns_.dbf',
13 'C:"oracle"oradata"JULIA"DATAFILE"o1_mf_undotbs1_37tc29mb_.dbf',
14 'C:"oracle"oradata"JULIA"DATAFILE"o1_mf_sysaux_37tc2gqc_.dbf',
15 'C:"oracle"oradata"JULIA"DATAFILE"o1_mf_users_37tc2tth_.dbf'
16 CHARACTER SET ZHS16GBK
17 ;
控制文件已创建。
然后将控制文件的名称等信息追加到参数文件中:
SQL> column ctl_files NEW_VALUE ctl_files;
SQL> SELECT CONCAT ('control_files=''',
2 CONCAT (REPLACE (VALUE, ', ', ''','''), '''')
3 ) ctl_files
4 FROM v$parameter WHERE NAME = 'control_files';
CTL_FILES
--------------------------------------------------------------------------------
control_files='C:"ORACLE"ORADATA"JULIA"CONTROLFILE"O1_MF_37Y7SZ9R_.CTL','C:"ORAC
LE"FLASH_RECOVERY_AREA"JULIA"CONTROLFILE"O1_MF_37Y7SZMK_.CTL'
SQL> host "echo &ctl_files >>C:"oracle"10.2.0"database"initjulia.ora";
注意:执行完以上命令后,需要检查参数文件的格式,如果控制文件名称未正确添加,可以手工调整一下。
完成了以上工作后,可以关闭数据库,再次启动数据库到mount状态,这时候新的控制文件已经发挥作用:
SQL> shutdown immediate;
ORA-01109: ??????
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> startup mount;
ORACLE 例程已经启动。
Total System Global Area 943718400 bytes
Fixed Size 1293960 bytes
Variable Size 239075704 bytes
Database Buffers 700448768 bytes
Redo Buffers 2899968 bytes
数据库装载完毕。
(8)完成数据库恢复。接下来再参考一下transport.sql中的推荐步骤:
ALTER DATABASE OPEN RESETLOGS;
-- Commands to add tempfiles to temporary tablespaces.
-- Online tempfiles have complete space information.
-- Other tempfiles may require adjustment.
ALTER TABLESPACE TEMP ADD TEMPFILE
SIZE 20971520 AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
-- End of tempfile additions.
现在需要通过RESETLOGS方式来重新生成日志文件,然后手工添加临时文件。
注意在迁移过程中如果两个平台的数据库版本完全一致,则以上步骤可以顺利执行,参考transport.sql可以顺利完成迁移。而本例的测试平台由于Linux平台的数据库版本为10.2.0.1,Windows平台版本为10.2.0.3,所以实际操作中还会有所不同,在执行RESETLOGS过程中,数据库会发生中断:
SQL> alter database open resetlogs;
alter database open resetlogs
*
第 1 行出现错误:
ORA-01092: ORACLE 实例终止。强制断开连接
检查日志发现以下提示:
Mon Jun 25 10:03:19 2007
Errors in file c:"oracle"admin"julia"udump"julia_ora_3596.trc:
ORA-00704: 引导程序进程失败
ORA-39700: 必须用 UPGRADE 选项打开数据库
Oracle要求以UPGRADE选项打开数据库,对数据库执行跨版本迁移。
继续参考transport.sql的最后部分:
SHUTDOWN IMMEDIATE
STARTUP UPGRADE PFILE='/opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora'
@@ ?/rdbms/admin/utlirp.sql
SHUTDOWN IMMEDIATE
STARTUP PFILE='/opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora'
-- The following step will recompile all PL/SQL modules.
-- It may take serveral hours to complete.
@@ ?/rdbms/admin/utlrp.sql
set feedback 6;
再次启动数据库到UPGRADE模式,由于之前的数据库中断,现在这些需要进行一点恢复工作:
SQL> startup upgrade;
ORACLE 例程已经启动。
Total System Global Area 943718400 bytes
Fixed Size 1293960 bytes
Variable Size 239075704 bytes
Database Buffers 700448768 bytes
Redo Buffers 2899968 bytes
数据库装载完毕。
ORA-01113: 文件 1 需要介质恢复
ORA-01110: 数据文件 1:'C:"ORACLE"ORADATA"JULIA"DATAFILE"O1_MF_SYSTEM_37TC1XNS_.DBF'
SQL> recover database;
完成介质恢复。
恢复完成之后启动数据库到UPGRADE模式:
SQL> shutdown immediate;
ORA-01109: 数据库未打开
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> startup upgrade;
ORACLE 例程已经启动。
Total System Global Area 943718400 bytes
Fixed Size 1293960 bytes
Variable Size 239075704 bytes
Database Buffers 700448768 bytes
Redo Buffers 2899968 bytes
数据库装载完毕。
数据库已经打开。
执行脚本?/rdbms/admin/utlirp.sql,这个脚本执行完成之后会有如下提示:
DOC>#######################################################################
DOC> utlirp.sql completed successfully. All PL/SQL objects in the
DOC> database have been invalidated.
DOC>
DOC> Shut down and restart the database in normal mode and run utlrp.sql to
DOC> recompile invalid objects.
DOC>#######################################################################
也就是说,这个脚本的作用是使数据库中的PL/SQL对象INVALID,然后通过utlrp.sql的重新编译,消除跨平台的兼容性影响。
按照transport.sql脚本提示的步骤,我们可以重新启动数据库来执行utlrp.sql脚本(由于本例涉及到版本迁移,需要再次启动数据库到upgrade模式,如果数据库版本相同,则可以直接启动数据库,执行utlrp.sql脚本完成最后的编译工作):
SQL> @@ ?/rdbms/admin/utlrp.sql
TIMESTAMP
-------------------------------------------------------------------------------
COMP_TIMESTAMP UTLRP_BGN 2007-06-25 10:27:57
…………
PL/SQL 过程已成功完成。
TIMESTAMP
-------------------------------------------------------------------------------
COMP_TIMESTAMP UTLRP_END 2007-06-25 10:39:43
PL/SQL 过程已成功完成。
utlrp.sql执行完成之后,需要再执行和数据库升级相关的脚本,这个脚本是catupgrd.sql:
SQL> @?/rdbms/admin/catupgrd.sql
这个脚本调用catlog.sql和 catproc.sql来重建字典对象等,在执行完这个脚本之后,可以关闭数据库后,正常打开数据库:
SQL> startup
ORACLE 例程已经启动。
Total System Global Area 943718400 bytes
Fixed Size 1293960 bytes
Variable Size 239075704 bytes
Database Buffers 700448768 bytes
Redo Buffers 2899968 bytes
数据库装载完毕。
数据库已经打开。
SQL> select count(*) from dba_objects where status='INVALID';
COUNT(*)
----------
86
已选择 1 行。
SQL> @?"rdbms"admin"utlrp.sql
catupgrd.sql脚本可能会使部分字典对象失效,可以再次运行utlrp.sql脚本来进行编译,编译完成后,不要忘记为数据库添加临时文件:
SQL> ALTER TABLESPACE TEMP ADD TEMPFILE
2 SIZE 20971520 AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
表空间已更改。
至此同字节序的跨平台迁移全部完成,当然由于版本的不同,整个过程稍微复杂了一些,不过这个过程对于跨平台的迁移及版本升级是一个很好的参考。
7. 实现数据迁移的高可用性
通过以上测试实际上可以确认,对于可传输表空间,可以很容易从Oracle 9i向Oracle 10g迁移。那么这种方法对于可用性要求极高的环境进行数据迁移或数据库迁移具有极大的便利。
如果进行数据库升级,通常的方法是通过DBUA(Database Upgrade Assistant,Oracle 10g引入的新工具)进行,但是DBUA存在的问题在于,操作过程过长,而且如果升级过程中出现问题,数据文件可能不能重新被使用,这就需要从备份中进行恢复,这使得业务连续性要求高的企业很难采用这种方法进行升级。
另外一种常见的迁移的方法是通过逻辑导出导入(EXP/IMP),但是这种方法对于不断变化的数据无能为力,所以通常也不可行。
那么现在,可传输表空间就成了一个可以考虑的快速迁移或升级方法。
Oracle有一个小组,专注于设计高可用性架构的实现,以帮助用户最大限度的提高系统可用性,Oracle有一个专有名词用来命名这类技术MAA(Maximum Availability Architecture)。OTN上MAA部分有一个Amadeus公司的实践案例,通过可传输表空间从Oracle 9i向Oracle 10g实现快速数据迁移。
当然这种方法的使用要考虑的还有很多,通过各种技术和方法的结合使用才能最终的达到快速迁移的目标。
Amadeus公司的迁移是在同类型平台不同主机之间进行的,其实现步骤大致如下:
(1) 在升级主机安装Oracle 9i版本,并创建生产库的DataGuard数据库,这个工作可以在线进行,不影响主节点的工作。
(2) 在升级主机安装Oracle 10gR2数据库软件,创建数据库;此时升级主机上存在了2个数据库。
(3) 整理不能通过transport tablespace处理的内容,如sequence、synonyms、grants等。
(4) 在升级割接时间,将主库置为只读,将日志全部应用到备机,业务影响从此时开始。
(5) 将备机的数据文件通过可传输表空间迁移至Oracle 10gR2数据库,并创建sequencee、synonyms、grants等对象,检查验证。
(6) 如果没有问题,则即可将业务切换至新的Oracle 10gR2数据库运行,业务恢复正常运行。
在这个迁移过程中,如果迁移失败,那么直接读写打开主库即可恢复业务的正常运行,回退非常方便。
使用这种方法,业务影响仅发生在以上(4)~(6)步,在OTN的案例中,Amadeus公司在实际操作中,10分钟之内就将一个大型数据库迁移到Oracle 10gR2,这种方式是一种非常有新意的创新性应用。在熟悉了Oracle的各项技术之后,通过不断实践和探索,我们就能够不断发现充满价值的Oracle应用。