《循序渐进Oracle:数据库管理、优化与备份恢复》一一1.4 使用模板创建数据库

  1. 云栖社区>
  2. 博客>
  3. 正文

《循序渐进Oracle:数据库管理、优化与备份恢复》一一1.4 使用模板创建数据库

异步社区 2017-05-02 16:04:00 浏览1585
展开阅读全文

本节书摘来自异步社区出版社《循序渐进Oracle:数据库管理、优化与备份恢复》一书中的第1章,第1.4节,作者:盖国强,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.4 使用模板创建数据库

循序渐进Oracle:数据库管理、优化与备份恢复
前面提到,除了定制数据库之外,还可以使用模板来创建数据库,接下来就让我们一起来了解一下使用模板创建数据库的过程。

1.4.1 启动创建

在1.1节中,我们提到可以通过命令行启动DBCA工具,可能更多的朋友是通过“开始”菜单中Oracle创建的快捷菜单来启动DBCA的,如图1-25所示,右图则是快捷方式的具体指向。

image

注意到这个快捷项的目标执行的是以下命令:

C:\Oracle\10.2.0\BIN\launch.exe C:\oracle\10.2.0\assistants\dbca dbca.cl

此处的dbca.cl文件和前面的dbca.bat批处理文件执行的功能是一致的:

Command=("C:\oracle\10.2.0\jdk\jre\BIN\JAVA" -Dsun.java2d.font.DisableAlgorithmicStyles=true 
-DORACLE_HOME="C:\oracle\10.2.0" -DJDBC_PROTOCOL=thin  
-mx128m –classpath …..OraInstaller.jar" oracle.sysman.assistants.dbca.Dbca)

那么DBCA为什么指向这个目录呢?这个目录又是做什么用的呢?

实际上这个目录是Oracle的缺省模板目录,当使用模板来创建数据库时,就用到了这个目录下的文件。

1.4.2 数据库创建模板

下面来看一下使用模板创建数据库的过程。

使用模板和前面的过程主要不同之处在于第二个步骤,在这里选择“定制数据库”之外的选项,就都使用了模板,并且包含了数据文件(eygle模板是我们之前保存的),如图1-26左图所示;使用模板创建数据库通常速度都会很快,原因就在于数据文件是从种子数据库中恢复出来的,而不需要创建文件及字典对象等信息,右图展示创建过程的第一个步骤就是“复制数据库文件”。

这里通过脚本说明一下通过模板创建数据库和定制数据库的不同。

首先eygle.sql脚本记录如下内容:

…… 
host C:\oracle\10.2.0\bin\orapwd.exe 
  file=C:\oracle\10.2.0\database\PWDeygle.ora password=&&sysPassword force=y 
@C:\oracle\admin\eygle\scripts\CloneRmanRestore.sql 
@C:\oracle\admin\eygle\scripts\cloneDBCreation.sql 
@C:\oracle\admin\eygle\scripts\postScripts.sql 
host "echo SPFILE='C:\oracle\10.2.0/dbs/spfileeygle.ora' 
          > C:\oracle\10.2.0\database\initeygle.ora" 
@C:\oracle\admin\eygle\scripts\postDBCreation.sql

image

该脚本首先调用的是CloneRmanRestore.sql脚本,该脚本记录如下内容:

C:\Oracle\admin\eygle\scripts>type CloneRmanRestore.sql 
connect "SYS"/"&&sysPassword" as SYSDBA 
set echo on 
spool C:\oracle\admin\eygle\scripts\CloneRmanRestore.log 
startup nomount pfile="C:\oracle\admin\eygle\scripts\init.ora"; 
@C:\oracle\admin\eygle\scripts\rmanRestoreDatafiles.sql;

这个脚本首先启动实例到Nomount模式,然后调用rmanRestoreDatafiles.sql来恢复文件。

1.4.3 rman的引入

rmanRestoreDatafiles.sql脚本是通过系统包dbms_backup_restore来恢复备份集中的文件,从而实现数据恢复,其主要内容如下:

set echo off; 
set serveroutput on; 
select TO_CHAR(systimestamp,'YYYYMMDD HH:MI:SS') from dual; 
variable devicename varchar2(255); 
declare 
omfname varchar2(512) := NULL; 
 done boolean; 
 begin 
  dbms_output.put_line(' '); 
  dbms_output.put_line(' Allocating device.... '); 
  dbms_output.put_line(' Specifying datafiles... '); 
    :devicename := dbms_backup_restore.deviceAllocate; 
  dbms_output.put_line(' Specifing datafiles... '); 
  dbms_backup_restore.restoreSetDataFile; 
   dbms_backup_restore.restoreDataFileTo(1, 
       'C:\oracle\oradata\eygle\SYSTEM01.DBF', 0, 'SYSTEM'); 
   dbms_backup_restore.restoreDataFileTo(2, 
       'C:\oracle\oradata\eygle\UNDOTBS01.DBF', 0, 'UNDOTBS1'); 
   dbms_backup_restore.restoreDataFileTo(3, 
       'C:\oracle\oradata\eygle\SYSAUX01.DBF', 0, 'SYSAUX'); 
   dbms_backup_restore.restoreDataFileTo(4, 
       'C:\oracle\oradata\eygle\USERS01.DBF', 0, 'USERS'); 
  dbms_output.put_line(' Restoring ... '); 
  dbms_backup_restore.restoreBackupPiece( 
     'C:\oracle\10.2.0\assistants\dbca\templates\Seed_Database.dfb', done); --种子数据库 
  if done then 
    dbms_output.put_line(' Restore done.'); 
  else 
    dbms_output.put_line(' ORA-XXXX: Restore failed '); 
  end if; 
  dbms_backup_restore.deviceDeallocate; 
 end; 
/

select TO_CHAR(systimestamp,'YYYYMMDD HH:MI:SS') from dual;```  
关于RMAN的有关知识,我们会在后面的章节详细介绍,但是关于dbms_backup_restore包这里有必要提前介绍一下。

当通过RMAN进行数据库备份时,RMAN会将多个数据文件写出到一个或多个备份文件(称为备份集)中,RMAN的相关备份信息或者存储在控制文件中,或者存储在RMAN的专用目录数据库(Catalog)中,如果RMAN的备份信息丢失,那么通常备份集中的文件是没有办法读取出来的,其他工具无法识别RMAN的备份集文件;而dbms_backup_restore就是针对这种情况提供的一种解决方案,dbms_backup_restore可以在数据库nomount状态下调用,直接从备份集中读取数据文件,功能十分强大。

DBMS_BACKUP_RESTORE包由dbmsbkrs.sql和prvtbkrs.plb这两个脚本创建,创建数据库时执行的catproc.sql 脚本会调用这两个脚本以创建包,这些脚本文件可以在$ORACLE_ HOME/rdbms/admin目录下找到,脚本文件中对包的内容有详细的介绍。

下面通过具体的例子来介绍一下这个工具的用法,以下是一次真实的恢复案例,由于控制文件丢失,只能通过DBMS_BACKUP_RESTORE包从备份集中恢复数据文件,当然恢复之前我们需要知道一些数据库的相关信息,了解备份集中包含了哪些文件。

首先启动数据库到nomount状态:

[oracle@jumper conner] $ sqlplus "/ as sysdba"
Connected to an idle instance.

SQL> startup nomount;
ORACLE instance started.

然后可以执行脚本,将数据文件恢复到指定目录:

SQL> DECLARE
 2  devtype varchar2(256);
 3  done boolean;
 4  BEGIN
 5  devtype:=sys.dbms_backup_restore.deviceAllocate (type=>'',ident=>'t1');
 6  sys.dbms_backup_restore.restoreSetDatafile;
 7  sys.dbms_backup_restore.restoreDatafileTo(dfnumber=>01,
          toname=>'/opt/oracle/oradata/conner/system01.dbf');
 8  sys.dbms_backup_restore.restoreDatafileTo(dfnumber=>02,
          toname=>'/opt/oracle/oradata/conner/undotbs01.dbf');
 9  sys.dbms_backup_restore.restoreDatafileTo(dfnumber=>03,
          toname=>'/opt/oracle/oradata/conner/users01.dbf');
10  sys.dbms_backup_restore.restoreBackupPiece(done=>done,
          handle=>'/opt/oracle/product/9.2.0/dbs/0ggmiabq_1_1', params=>null);
11  sys.dbms_backup_restore.deviceDeallocate;
12 END;
13 /

PL/SQL procedure successfully completed.

至此,从备份集中读取文件完毕,但是由于没有控制文件,就需要重建一个控制文件用于恢复,创建控制文件的脚本可以自己根据经验编写,也可以根据备份的文本进行修改,当然也可以从其他数据库中转储一个控制文件脚本,仿照改写。

正常情况下,可以通过如下的命令将控制文件的创建语句转储到跟踪文件中(位于udump目录中):

SQL> alter database backup controlfile to trace;
Database altered.
可以找到trace文件,编辑、执行重建控制文件的需要部分:

SQL> startup nomount;
ORACLE instance started.
SQL> set echo on
SQL> @ctl.sql
SQL> CREATE CONTROLFILE REUSE DATABASE "CONNER" RESETLOGS ARCHIVELOG
 2 -- SET STANDBY TO MAXIMIZE PERFORMANCE
 3   MAXLOGFILES 5
 4   MAXLOGMEMBERS 3
 5   MAXDATAFILES 100
 6   MAXINSTANCES 1
 7   MAXLOGHISTORY 1361
 8 LOGFILE
 9  GROUP 1 '/opt/oracle/oradata/conner/redo01.log' SIZE 10M,
10  GROUP 2 '/opt/oracle/oradata/conner/redo02.log' SIZE 10M,
11  GROUP 3 '/opt/oracle/oradata/conner/redo03.log' SIZE 10M
12 -- STANDBY LOGFILE
13 DATAFILE
14  '/opt/oracle/oradata/conner/system01.dbf',
15  '/opt/oracle/oradata/conner/undotbs01.dbf',
16  '/opt/oracle/oradata/conner/users01.dbf'
17 CHARACTER SET ZHS16GBK
18 ;

Control file created.

如果存在部分归档日志,创建控制文件之后可以执行恢复:

SQL> recover database using backup controlfile until cancel;
ORA-00279: change 240560269 generated at 06/09/2005 17:33:48 needed for thread 1
ORA-00289: suggestion : /oradata/conner/archive/1_7.dbf
ORA-00280: change 240560269 for thread 1 is in sequence #7

Specify log: {=suggested | filename | AUTO | CANCEL}
AUTO
ORA-00279: change 240600632 generated at 06/10/2005 10:42:26 needed for thread 1
ORA-00289: suggestion : /oradata/conner/archive/1_8.dbf
ORA-00280: change 240600632 for thread 1 is in sequence #8
ORA-00278: log file '/oradata/conner/archive/1_7.dbf' no longer needed for this recovery

Specify log: {=suggested | filename | AUTO | CANCEL}
AUTO
ORA-00279: change 240620884 generated at 06/10/2005 10:45:42 needed for thread 1
ORA-00289: suggestion : /oradata/conner/archive/1_9.dbf
ORA-00280: change 240620884 for thread 1 is in sequence #9
ORA-00278: log file '/oradata/conner/archive/1_8.dbf' no longer needed for this recovery

ORA-00283: recovery session canceled due to errors
ORA-00600: internal error code, arguments: [3020], [4242465], [1], [9], [314], [272], [], []
ORA-10567: Redo is inconsistent with data block (file# 1, block# 48161)
ORA-10564: tablespace SYSTEM
ORA-01110: data file 1: '/opt/oracle/oradata/conner/system01.dbf'
ORA-10560: block type 'DATA SEGMENT HEADER - UNLIMITED'

ORA-01112: media recovery not started
SQL> recover database using backup controlfile until cancel;
ORA-00279: change 240620949 generated at 06/10/2005 10:45:44 needed for thread 1
ORA-00289: suggestion : /oradata/conner/archive/1_9.dbf
ORA-00280: change 240620949 for thread 1 is in sequence #9

Specify log: {=suggested | filename | AUTO | CANCEL}
cancel
Media recovery cancelled.`

恢复到最后可用日志后,通过resetlogs方式打开数据库:


SQL> alter database open resetlogs; 
Database altered. 
SQL> select name from v$datafile; 
NAME 
------------------------------------------------------------ 
/opt/oracle/oradata/conner/system01.dbf 
/opt/oracle/oradata/conner/undotbs01.dbf 
/opt/oracle/oradata/conner/users01.dbf

至此恢复完成。这是一次常规恢复,dbms_backup_restore的功能远不止于此,还可以通过该包恢复备份集中的控制文件、归档日志等文件。

继续前面的讨论,rmanRestoreDatafiles.sql脚本通过dbms_backup_restore包从种子文件Seed_Database.dfb恢复出数据文件,来看一下模板目录中存放的模板和种子数据库(自定义的模板也存放在这个目录中):

C:\Oracle\admin\eygle\scripts>dir C:\oracle\10.2.0\assistants\dbca\templates 
2005-08-30 17:31       5,893 Data_Warehouse.dbc 
2005-09-07 13:02      983,040 example.dmp 
2005-09-07 13:02    20,897,792 example01.dfb 
2005-08-30 17:31       5,770 General_Purpose.dbc 
2005-05-16 15:49      12,411 New_Database.dbt 
2005-09-07 13:02     7,061,504 Seed_Database.ctl 
2005-09-07 13:02    95,543,296 Seed_Database.dfb 
2005-08-30 17:31       5,829 Transaction_Processing.dbc

Seed_Database.dfb文件就是包含种子文件的一个备份集。

1.4.4 克隆数据库

数据文件具备了,接下来是通过这些文件“克隆”一个数据库,这个工作由cloneDBCreation.sql脚本继续执行,这个脚本更为复杂,下面分开介绍一下。

首先根据指定的数据库名称(测试数据库指定的名称为eygle)创建一个控制文件:

connect "SYS"/"&&sysPassword" as SYSDBA 
set echo on 
spool C:\oracle\admin\eygle\scripts\cloneDBCreation.log 
Create controlfile reuse set database "eygle" 
MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100 
Datafile 
'C:\oracle\oradata\eygle\SYSTEM01.DBF', 
'C:\oracle\oradata\eygle\UNDOTBS01.DBF', 
'C:\oracle\oradata\eygle\SYSAUX01.DBF', 
'C:\oracle\oradata\eygle\USERS01.DBF' 
LOGFILE GROUP 1 ('C:\oracle/oradata/eygle/redo01.log') SIZE 51200K, 
GROUP 2 ('C:\oracle/oradata/eygle/redo02.log') SIZE 51200K, 
GROUP 3 ('C:\oracle/oradata/eygle/redo03.log') SIZE 51200K RESETLOGS;

然后通过dbms_backup_restore包清空dbid等信息:

exec dbms_backup_restore.zerodbid(0);

看到这里再次使用到了dbms_backup_restore包,zeroDbid是包中的一个过程,用于清空数据文件头的部分信息,新的dbid在之后的控制文件创建时可以被计算,对于数据库克隆,这是必须的。

zeroDbid有一个输入参数,即文件号:

PROCEDURE zeroDbid(fno    IN  binary_integer);

当fno==0时,控制文件中包含的所有数据文件头都将被清零,zeroDbid主要用于清除数据文件头的3类信息:Database id信息、Checksum信息和Checksum符号位信息。

继续看这个脚本,清零完成之后,数据库重新启动,控制文件被重新创建,此时新的dbid被计算并最终写入所有数据文件:

shutdown immediate; 
startup nomount pfile="C:\oracle\admin\eygle\scripts\initeygleTemp.ora"; 
Create controlfile reuse set database "eygle" 
MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100 
Datafile 
'C:\oracle\oradata\eygle\SYSTEM01.DBF', 
'C:\oracle\oradata\eygle\UNDOTBS01.DBF', 
'C:\oracle\oradata\eygle\SYSAUX01.DBF', 
'C:\oracle\oradata\eygle\USERS01.DBF' 
LOGFILE GROUP 1 ('C:\oracle/oradata/eygle/redo01.log') SIZE 51200K, 
GROUP 2 ('C:\oracle/oradata/eygle/redo02.log') SIZE 51200K, 
GROUP 3 ('C:\oracle/oradata/eygle/redo03.log') SIZE 51200K RESETLOGS;

注意,在启动数据库时Oracle使用了一个临时的参数文件initeygleTemp.ora,在这个参数文件的最后一行设置了一个内部参数:

C:\Oracle\admin\eygle.t\scripts>tail -1 initeygleTemp.ora 
_no_recovery_through_resetlogs=true

_no_recovery_through_resetlogs这个参数的作用是什么呢?可以从数据库中找到一点说明:

SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ 
 2  FROM SYS.x$ksppi x, SYS.x$ksppcv y 
 3  WHERE x.inst_id = USERENV ('Instance') 
 4   AND y.inst_id = USERENV ('Instance') 
 5   AND x.indx = y.indx AND x.ksppinm LIKE '%&par%'; 
Enter value for par: no_reco 
NAME              VALUE DESCRIB 
------------------------------ ----- ---------------------------------------------- 
_no_recovery_through_resetlogs FALSE no recovery through this resetlogs operation

这个参数用于限制恢复能否跨越resetlogs,对于数据库的恢复来说,resetlogs通常意味着不完全恢复,在数据库resetlogs打开之后,控制文件中的很多信息被改写,在Oracle 10g之前,如果数据库resetlogs打开,那么将不再能够通过当前的控制文件再次进行resetlogs点之前的恢复,而Oracle 10g改变了这个历史。

在Oracle 10g中,即使通过resetlogs方式打开了数据库,Oracle仍然支持再次从resetlogs时间点之前进行恢复;在Clone数据库时,Oracle设置这个参数为True,意思就是不允许再次进行跨越resetlogs时间点的恢复。关于这部分内容,我们将在后面章节进行更为详细的介绍。

继续解读这个脚本,接下来Oracle设置restricted session模式,resetlogs打开数据库:

alter system enable restricted session; 
alter database "eygle" open resetlogs;
修改global_name,添加临时文件等:

alter database rename global_name to "eygle"; 
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\oracle\oradata\eygle\TEMP01.DBF' SIZE 20480K REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED; 
select tablespace_name from dba_tablespaces where tablespace_name='USERS'; 
select sid, program, serial#, username from v$session;
由于种子数据库的字符集通常与用户要求的不符,接下来Oracle通过内部操作强制更改了字符集、国家字符集(这个内容在后面的章节中有详细的介绍):

alter database character set INTERNAL_CONVERT ZHS16GBK; 
alter database national character set INTERNAL_CONVERT AL16UTF16;
最后修改用户口令,禁用restricted session模式,这个克隆过程执行完毕:

alter user sys identified by "&&sysPassword"; 
alter user system identified by "&&systemPassword"; 
alter system disable restricted session;

至此,种子数据库已经按照用户的意图脱胎换骨得以重生。

1.4.5 传输表空间技术

在很多Oracle文档中,可能大家都注意过Oracle用来进行测试的一个表空间,这个表空间中有一系列预置的用户和数据,可以用于数据库或BI的很多测试实验。

这个表空间在使用模板建库时是可以选择的,在如图1-27所示的这个界面中,可以选择建库时包含这个范例表空间(缺省是未选择的)。

如果选择了包含示例方案,则cloneDBCreation.sql脚本将会有所改变,主要增加了如下语句:

connect "SYS"/"&&sysPassword" as SYSDBA 
@C:\oracle\10.2.0\demo\schema\mkplug.sql &&sysPassword change_on_install change_on_install 
change_on_install change_on_install change_on_install change_on_install 
C:\oracle\10.2.0\assistants\dbca\templates\example.dmp 
C:\oracle\10.2.0\assistants\dbca\templates\example01.dfb
C:\oracle\oradata\eygle\example01.dbf C:\oracle\admin\eygle\scripts\ "'SYS/&&sysPassword as SYSDBA'";

image

看到这里,再次引用了模板目录中的文件:

C:\>dir C:\oracle\10.2.0\assistants\dbca\templates\ex* 

2005-09-07 13:02      983,040 example.dmp 
2005-09-07 13:02    20,897,792 example01.dfb

通过mkplug.sql脚本来加载这个范例表空间,来看一下这个脚本的主要内容。

同样,最重要的是通过dbms_backup_restore包从example01.dfb文件中恢复数据文件:

SELECT TO_CHAR(systimestamp, 'YYYYMMDD HH:MI:SS') FROM dual; 
variable new_datafile varchar2(512) 
declare 
 done boolean; 
 v_db_create_file_dest VARCHAR2(512); 
 devicename varchar2(255); 
 data_file_id number; 
 rec_id number; 
 stamp number; 
 resetlogs_change number; 
 creation_change number; 
 checkpoint_change number; 
 blksize number; 
 omfname varchar2(512); 
 real_file_name varchar2(512); 

 begin 
  dbms_output.put_line(' '); 
  dbms_output.put_line(' Allocating device.... '); 
  dbms_output.put_line(' Specifying datafiles... '); 
    devicename := dbms_backup_restore.deviceAllocate; 
  dbms_output.put_line(' Specifing datafiles... '); 
  SELECT MAX(file_id)+1 INTO data_file_id FROM dba_data_files; 
  SELECT value INTO v_db_create_file_dest FROM v$parameter WHERE name ='db_create_file_dest'; 
  IF v_db_create_file_dest IS NOT NULL 
   THEN 
   dbms_backup_restore.restoreSetDataFile; 
   dbms_backup_restore.getOMFFileName('EXAMPLE',omfname); 
   dbms_backup_restore.restoreDataFileTo(data_file_id, omfname, 0,'EXAMPLE'); 
   ELSE 
   dbms_backup_restore.restoreSetDataFile; 
   dbms_backup_restore.restoreDataFileTo(data_file_id,'&data_file_name'); 
   END IF; 
  dbms_output.put_line(' Restoring ... '); 
  dbms_backup_restore.restoreBackupPiece('&data_file_backup', done); 
  SELECT max(recid) INTO rec_id FROM v$datafile_copy; 

  -- Now get the real file name. It could be also OMF filename 
  SELECT name, stamp, resetlogs_change#, creation_change#, checkpoint_change#,block_size 
  INTO real_file_name, stamp,resetlogs_change, creation_change, checkpoint_change, blksize 
  FROM V$DATAFILE_COPY 
   WHERE recid = rec_id and file# = data_file_id; 

  -- Uncatalog the file from V$DATAFILE_COPY. This important. 
  dbms_backup_restore.deleteDataFileCopy(recid => rec_id, 
                   stamp => stamp, 
                   fname => real_file_name, 
                   dfnumber => data_file_id, 
                   resetlogs_change => resetlogs_change, 
                   creation_change => creation_change, 
                   checkpoint_change => checkpoint_change, 
                   blksize => blksize, 
                   no_delete => 1, 
                   force => 1); 
  -- Set the bindvariable to the real filename                    
  :new_datafile := real_file_name; 

  if done then 
    dbms_output.put_line(' Restore done.'); 
  else 
    dbms_output.put_line(' ORA-XXXX: Restore failed '); 
  end if; 
 end; 
/

这个恢复完成之后,接下来最重要的部分就是通过传输表空间技术将example表空间导入到当前的数据库。

考虑一下这种情况,当进行跨数据库迁移时,需要将一个用户表空间中的数据迁移到另外一个数据库,应该使用什么样的方法呢?

最常规的做法可能是通过EXP工具将数据全部导出,然后在目标数据库上IMP导入,可是这种方法可能会比较缓慢。EXP工具同时还提供另外一种技术——可传输表空间技术,可以用于加快这个过程。

在exp -help的帮助中,可以看到这样一个参数:

TRANSPORT_TABLESPACE 导出可传输的表空间元数据 (N)

通过这个选项,我们可以对一组自包含、只读的表空间只导出元数据,然后在操作系统层将这些表空间的数据文件拷贝至目标平台,并将元数据导入数据字典(这个过程称为插入,plugging),即完成迁移。但是注意,传输表空间技术不能应用于SYSTEM表空间或SYS用户拥有的对象。

对于可传输表空间有一个重要概念:自包含(Self-Contained)。

在表空间传输中,要求表空间集为自包含的,自包含表示用于传输的内部表空间集没有引用指向外部表空间集。自包含分为两种:一般自包含表空间集和完全(严格)自包含表空间集。

常见的以下情况是违反自包含原则的。

boll 索引在内部表空间集,而表在外部表空间集(相反地,如果表在内部表空间集,而索引在外部表空间集,则不违反自包含原则)。

boll 分区表一部分区在内部表空间集,一部分在外部表空间集(对于分区表,要么全部包含在内部表空间集中,要么全不包含)。

boll 如果在传输表空间时同时传输约束,则对于引用完整性约束,约束指向的表在外部表空间集,则违反自包含约束;如果不传输约束,则与约束指向无关。

boll 表在内部表空间集,而lob列在外部表空间集,则违反自包含约束。

通常可以通过系统包DBMS_TTS来检查表空间是否自包含,验证可以以两种方式执行:非严格方式和严格方式。

以下是一个简单的验证过程,假定在eygle表空间存在一个表eygle,其上存在索引存储在USERS表空间:

SQL> create table eygle as select rownum id ,username from dba_users; 
SQL> create index ind_id on eygle(id) tablespace users;

以SYS用户执行非严格自包含检查(full_check=false):

SQL> connect / as sysdba 
SQL> exec dbms_tts.transport_set_check('EYGLE', TRUE); 
PL/SQL procedure successfully completed. 

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS; 
no rows selected

执行严格自包含检查(full_check=true):

SQL> exec dbms_tts.transport_set_check('EYGLE', TRUE, True); 
PL/SQL procedure successfully completed. 

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS; 
VIOLATIONS 
-------------------------------------------------------------------------------------- 
Index EYGLE.IND_ID in tablespace USERS points to table EYGLE.EYGLE in tablespace EYGLE

反过来对于USERS表空间来说,非严格检查也是无法通过的:

SQL> exec dbms_tts.transport_set_check('USERS', TRUE); 
PL/SQL procedure successfully completed. 

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS;
VIOLATIONS 
---------------------------------------------------------------------------------------- 
Index EYGLE.IND_ID in tablespace USERS points to table EYGLE.EYGLE in tablespace EYGLE

但是,可以对多个表空间同时传输,则一些自包含问题就可以得到解决:

SQL> exec dbms_tts.transport_set_check('USERS,EYGLE', TRUE, True); 
PL/SQL procedure successfully completed. 

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS; 
no rows selected

表空间自包含确认之后,进行表空间传输就很方便了,一般包含如下几个步骤。

(1)将表空间设置为只读。

alter tablespace users read only;

(2)导出表空间。在操作系统提示符下执行:

exp username/passwd tablespaces=users transport_tablespace=y file=exp_users.dmp

此处的导出文件只包含元数据,所以导出文件很小,导出速度也会很快。

(3)转移。将导出的元数据文件(此处是exp_users.dmp)和传输表空间的数据文件(此处是users表空间的数据文件user01.dbf)转移至目标主机(转移过程如果使用FTP方式,应该注意使用二进制方式)。

(4)传输。在目标数据库将表空间插入到数据库中,完成表空间传输。在操作系统命令提示符下执行以下语句:

imp username/passwd tablespaces=users transport_tablespace=y file=exp_users.dmp datafiles='users01.dbf'

了解了Oracle的可传输表空间技术后,来看一下example表空间的插入,以下脚本仍然来自mkplug.sql脚本:

-- 
-- Importing the metadata and plugging in the tablespace at the same 
-- time, using the restored database file 
-- 
DEFINE imp_logfile = &log_path.tts_example_imp.log 

-- When importing use filename got after restore is finished 
host imp "'sys/&&password_sys AS SYSDBA'" transport_tablespace=y file=&imp_file log=&imp_logfile datafiles='&datafile' tablespaces=EXAMPLE tts_owners=hr,oe,pm,ix,sh

完成plugging之后,这个表空间就被包含在了新建的数据库之中。

1.4.6 跨平台表空间传输

需要注意的是,在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> create tablespace trans 
 2 datafile '/data2/ora10g/oradata/mars/trans.dbf' size 10M; 
SQL> create user trans identified by trans default tablespace trans; 
SQL> grant connect,resource to trans; 
SQL> connect trans/trans 
SQL> create table test as select * from dict; 
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的convert命令转换文件格式:

$ 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

4.文件传输
通过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.
5.目标数据库的导入
在目标数据库中,也可以使用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 where name like ‘%TRANS%’; 
NAME 
------------------------------------------------------------ 
D:\ORADATA\EYGLE\DATAFILE\TRANS01.DBF 
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 成功完成

6.同字节序文件的跨平台
前面说过,当一个Little Endian的系统试图从一个Big Endian的系统中读取数据时,就需要通过转换,否则不同的字节顺序将导致数据不能被正确读取。那么另外一个问题出现了,如果字节序相同的平台进行文件交互,数据能否被正确读取呢?

理论上的确是可以的,但是由于在不同的平台上操作系统会在数据文件头写上系统信息,这部分信息无法跨越平台,所以仍然会导致跨平台的文件无法被数据库正确识别(Oracle10g中同字节序平台数据文件头不再存在跨平台的迁移问题)。

接下来让我们通过Windows和Linux平台来进行一个跨平台测试,相信通过这个测试可以对以上提出的问题作出一个很好的回答。

实验环境一:Windows XP + Oracle10g 10.2.0.1。

SQL> select * from v$version where rownum <2; 
BANNER 
---------------------------------------------------------------- 
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

实验环境二:Red Hat Enterprise Linux AS release 3 + Oracle 9iR2 9.2.0.4。

SQL> select * from v$version where rownum <2; 
BANNER 
---------------------------------------------------------------- 
Oracle9i Enterprise Edition Release 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 
2007-03-22 17:41     5,251,072 O1_MF_USERS_2G8OJYYS_.DBF 

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 
    0 Linux IA (32-bit)            Little

首先在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; 
SQL> grant connect,resource to eyglee; 
SQL> connect eyglee/eyglee 
Connected. 
SQL> create table eyglee as select * from dict; 
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* 
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:oradataEYGLEDATAFILE>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.

经由常规路径由 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中使用。

7.Oracle10g同字节序跨平台迁移
在Oracle10g中,同字节序跨平台的文件头信息Oracle会自动改写,不再需要转换。我们看以下测试:

[oracle@danaly oradata] $ sqlplus "/ as sysdba" 

SQL*Plus: Release 10.2.0.1.0 - Production on Thu Jul 12 15:14:21 2007 
Copyright (c) 1982, 2005, Oracle. All rights reserved. 

SQL> alter database mount; 
Database altered. 

SQL> alter database open;   
Database altered. 

SQL> select name from v$datafile; 
NAME 
-------------------------------------------------------------------------------- 
/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_system_37tc1xns_.dbf 
/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_undotbs1_37tc29mb_.dbf 
/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_sysaux_37tc2gqc_.dbf 
/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_users_37tc2tth_.dbf 

SQL> show parameter comp 
NAME                 TYPE    VALUE 
------------------------------------ ----------- ------------------------------ 
compatible              string   10.2.0.1.0 
nls_comp               string 
plsql_compiler_flags         string   INTERPRETED, NON_DEBUG 
plsql_v2_compatibility        boolean   FALSE 
SQL> create tablespace trans 
 2 datafile '/opt/oracle/oradata/eygle/EYGLE/datafile/trans.dbf' size 10M; 
Tablespace created. 

SQL> create user trans identified by trans default tablespace trans; 
SQL> grant connect,resource to trans; 
SQL> connect trans/trans 
Connected. 
SQL> create table test as select * from dict; 
Table created. 
SQL> select count(*) from test; 
 COUNT(*) 
---------- 
    615 
SQL> connect / as sysdba 
Connected. 
SQL> alter tablespace trans read only; 

Tablespace altered.

导出元数据,准备表空间迁移:

[oracle@]$ exp \'/ as sysdba\' tablespaces=trans transport_tablespace=y file=exp_trans.dmp 

Export: Release 10.2.0.1.0 - Production on Thu Jul 12 15:28:24 2007 
Copyright (c) 1982, 2005, Oracle. All rights reserved. 
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. 
[oracle@danaly oradata] $ ls -l exp_trans.dmp 
-rw-r--r-- 1 oracle dba 16384 Jul 12 15:28 exp_trans.dmp

然后我们可以直接将这两个文件传输到Windows平台上,在数据库中执行必要的准备步骤:

SQL> create user trans identified by trans; 
用户已创建。 

SQL> grant connect,resource to trans; 
授权成功。

接下来执行导入:

C:\oracle\oradata\EYGLE\DATAFILE>imp '/ as sysdba' tablespaces=trans transport_tablespace=y file=exp_trans.dmp datafiles=C:\oracle\oradata\EYGLE\DATAFILE\trans.dbf 

Import: Release 10.2.0.3.0 - Production on 星期四 7月 12 15:55:30 2007 
Copyright (c) 1982, 2005, Oracle. All rights reserved. 

经由常规路径由 EXPORT:V10.02.01 创建的导出文件 
即将导入可传输的表空间元数据... 
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入 
. 正在将 SYS 的对象导入到 SYS 
. 正在将 SYS 的对象导入到 SYS 
. 正在将 TRANS 的对象导入到 TRANS 
. . 正在导入表             "TEST" 
. 正在将 SYS 的对象导入到 SYS 
成功终止导入, 没有出现警告。
我们看到这个文件可以直接被Windows上的系统识别。

SQL> select count(*) from trans.test; 
 COUNT(*) 
---------- 
    615 
SQL> select tablespace_name,status from dba_tablespaces; 
TABLESPACE_NAME        STATUS 
------------------------------ --------- 
SYSTEM             ONLINE 
UNDOTBS1            ONLINE 
SYSAUX             ONLINE 
TEMP              ONLINE 
USERS             ONLINE 
TRANS             READ ONLY
8.Oracle10g同字节序跨平台迁移的增强
基于上一节的测试我们知道,在Oracle10gR2中,Oracle开始支持同字节序数据库的跨平台迁移。这一技术实现有以下几点注意事项。

boll 源平台和目的平台需要具有相同的字节序。

boll 重做日志文件和控制文件不会传输,迁移之后需要重建控制文件使用RESETLOGS方式打开数据库;临时文件不会被传输。

boll 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个部分。

第一部分列出需要修改的参数:

# 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"

第二部分列出了建议Review的参数:

# Please review the values of the following parameters: 
 remote_login_passwordfile= "EXCLUSIVE" 
 db_domain        = "" 
 dispatchers       = "(PROTOCOL=TCP) (SERVICE=eygleXDB)"

第三部分列出了来自于源数据库的一些特殊设置,这些参数可以酌情修改:

# 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 例程已经启动。

接下来创建控制文件:

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; 
控制文件已创建。

然后将控制文件的名称等信息追加到参数文件中:

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:oracle10.2.0databaseinitjulia.ora";
注意:

执行完以上命令后,需要检查参数文件的格式,如果控制文件名称未正确添加,可以手工调整一下。
完成了以上工作后,可以关闭数据库,再次启动数据库到Mount状态,这时候新的控制文件已经发挥作用:

SQL> shutdown immediate; 
ORA-01109: 数据库未打开 

已经卸载数据库。 
ORACLE 例程已经关闭。 
SQL> startup mount; 
ORACLE 例程已经启动。 
数据库装载完毕。

(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:oracleadminjuliaudumpjulia_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 例程已经启动。 
数据库装载完毕。 
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 例程已经启动。 
数据库装载完毕。 
数据库已经打开。

执行脚本?/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 例程已经启动。 
数据库装载完毕。 
数据库已经打开。 
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;

表空间已更改。
至此,同字节序的跨平台迁移全部完成,当然由于版本的不同,整个过程稍微复杂了一些,不过,这个过程对于跨平台的迁移及版本升级是一个很好的参考。

9.实现数据迁移的高可用性
通过以上测试实际上可以确认,对于可传输表空间,可以很容易从Oracle 9i向Oracle 10g迁移。那么这种方法对于可用性要求极高的环境进行数据迁移或数据库迁移具有极大的便利。

如果进行数据库升级,通常的方法是通过DBUA(Database Upgrade Assistant,Oracle 10g引入的新工具)进行,但是DBUA存在的问题在于,操作过程过长,而且如果升级过程中出现问题,数据文件可能不能重新被使用,这就需要从备份中进行恢复,这使得业务连续性要求高的企业很难采用这种方法进行升级。

另外一种常见的迁移方法是通过逻辑导出导入(EXP/IMP),但是这种方法对于不断变化的数据无能为力,所以通常也不可行。那么现在,可传输表空间就成了一个可以考虑的快速迁移或升级方法。

Oracle有一个小组,专注于设计高可用性架构的实现,以帮助用户最大限度的提高系统可用性,Oracle有一个专有名词用来命名这类技术——MAA(Maximum Availability Architecture ,MAA)。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应用。

1.4.7 文件系统与ASM的切换

在进行表空间迁移时,如果是从文件系统到文件系统的迁移很容易实现,但是如果是从文件系统到ASM则需要多一点步骤。类似前面的测试,如果在ASM环境中执行同样的导入命令:

imp \'/ as sysdba\' tablespaces=trans transport_tablespace=y 
              file=exp_trans.dmp datafiles=/opt/oracle/trans.dbf

则简单的导入之后会出现如下的效果,新导入的文件位于文件系统之上,这显然是不希望看到的,我们需要将文件系统文件转移到ASM磁盘组上去:

SQL> select name from v$datafile; 
NAME 
-------------------------------------------------------------------------------- 
+DATADG/rac/datafile/system.259.722961061 
+DATADG/rac/datafile/undotbs1.260.722961083 
+DATADG/rac/datafile/sysaux.261.722961087 
+DATADG/rac/datafile/undotbs2.263.722961097 
+DATADG/rac/datafile/users.264.722961099 
/opt/oracle/trans.dbf

文件转移可以通过RMAN来进行,但是首次尝试遇到了RMAN-20201错误:

[oracle@rac1 oracle] $ rman target / 

Recovery Manager: Release 10.2.0.4.0 - Production on Wed Sep 1 14:24:37 2010 
Copyright (c) 1982, 2007, Oracle. All rights reserved. 
connected to target database: RAC (DBID=2310943069) 

RMAN> backup as copy datafile '/opt/oracle/trans.dbf' format '+DATADG'; 

Starting backup at 01-SEP-10 
using target database control file instead of recovery catalog 
allocated channel: ORA_DISK_1 
channel ORA_DISK_1: sid=124 instance=rac1 devtype=DISK 
RMAN-00571: =========================================================== 
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS =============== 
RMAN-00571: =========================================================== 
RMAN-03002: failure of backup command at 09/01/2010 14:25:21 
RMAN-20201: datafile not found in the recovery catalog 
RMAN-06010: error while looking up datafile: /opt/oracle/trans.dbf

这个错误是由于TRANS表空间刚刚导入到数据库中,处于只读状态,并未被Catalog记录感知,通过对这个文件进行特定操作,如读写变更,则可以消除此错误:

SQL> select tablespace_name,status from dba_tablespaces where tablespace_name=’TRANS’; 
TABLESPACE_NAME        STATUS 
------------------------------ --------- 
TRANS             READ ONLY

RMAN中的Schema信息尚未记录该表空间:

RMAN> report schema; 

Report of database schema 

List of Permanent Datafiles 
=========================== 
File Size(MB) Tablespace      RB segs Datafile Name 
---- -------- -------------------- ------- ------------------------ 
1  300   SYSTEM        ***   +DATADG/rac/datafile/system.259.722961061 
2  200   UNDOTBS1       ***   +DATADG/rac/datafile/undotbs1.260.722961083 
3  280   SYSAUX        ***   +DATADG/rac/datafile/sysaux.261.722961087 
4  200   UNDOTBS2       ***   +DATADG/rac/datafile/undotbs2.263.722961097 
5  5    USERS        ***   +DATADG/rac/datafile/users.264.722961099 
6  512   STREAM_TBS      ***   +DATADG/rac/datafile/stream_tbs.268.725126097 
7  1    TESTTBS1       ***   +DATADG/rac/datafile/testtbs1.269.726592535 

List of Temporary Files 
======================= 
File Size(MB) Tablespace      Maxsize(MB) Tempfile Name 
---- -------- -------------------- ----------- -------------------- 
1  20    TEMP         32767    +DATADG/rac/tempfile/temp.262.722961089

在数据库内部对该表空置读写访问:

SQL> alter tablespace trans read write; 
Tablespace altered.
然后可以看到该表空间被Catalog所记录,当然这里的信息是来自控制文件的:

RMAN> report schema; 

using target database control file instead of recovery catalog 
Report of database schema 

List of Permanent Datafiles 
=========================== 
File Size(MB) Tablespace      RB segs Datafile Name 
---- -------- -------------------- ------- ------------------------ 
1  300   SYSTEM        ***   +DATADG/rac/datafile/system.259.722961061 
2  200   UNDOTBS1       ***   +DATADG/rac/datafile/undotbs1.260.722961083 
3  280   SYSAUX        ***   +DATADG/rac/datafile/sysaux.261.722961087 
4  200   UNDOTBS2       ***   +DATADG/rac/datafile/undotbs2.263.722961097 
5  5    USERS        ***   +DATADG/rac/datafile/users.264.722961099 
6  512   STREAM_TBS      ***   +DATADG/rac/datafile/stream_tbs.268.725126097 
7  1    TESTTBS1       ***   +DATADG/rac/datafile/testtbs1.269.726592535 
8  10    TRANS        ***   /opt/oracle/trans.dbf 

List of Temporary Files 
======================= 
File Size(MB) Tablespace      Maxsize(MB) Tempfile Name 
---- -------- -------------------- ----------- -------------------- 
1  20    TEMP         32767    +DATADG/rac/tempfile/temp.262.722961089

接下来将表空间状态再改为只读:

SQL> alter tablespace trans read only; 
Tablespace altered.

通过RMAN进行镜像拷贝:

RMAN> backup as copy datafile '/opt/oracle/trans.dbf' format '+DATADG'; 

Starting backup at 01-SEP-10 
using target database control file instead of recovery catalog 
allocated channel: ORA_DISK_1 
channel ORA_DISK_1: sid=130 instance=rac1 devtype=DISK 
channel ORA_DISK_1: starting datafile copy 
input datafile fno=00008 name=/opt/oracle/trans.dbf 
output filename=+DATADG/rac/datafile/trans.270.728577593 tag=TAG20100901T143951 recid=2 stamp=728577592 
channel ORA_DISK_1: datafile copy complete, elapsed time: 00:00:01 
Finished backup at 01-SEP-10

切换之前需要将表空间离线,否则会出现错误:

RMAN> switch datafile '/opt/oracle/trans.dbf' to copy; 

RMAN-00571: =========================================================== 
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS =============== 
RMAN-00571: =========================================================== 
RMAN-03002: failure of switch to copy command at 09/01/2010 14:40:58 
RMAN-06572: database is open and datafile 8 is not offline

将表空间离线:

SQL> alter tablespace trans offline; 

Tablespace altered.
执行切换:

RMAN> switch datafile '/opt/oracle/trans.dbf' to copy; 

datafile 8 switched to datafile copy "+DATADG/rac/datafile/trans.270.728577593"

现在转换后的表空间已经被转移到了ASM磁盘组中,此时可以将表空间Online,如果操作期间有过事务变更,还可能需要恢复:

SQL> alter tablespace trans online; 
Tablespace altered. 

SQL> select name from v$datafile; 
NAME 
-------------------------------------------------------------------------------- 
+DATADG/rac/datafile/system.259.722961061 
+DATADG/rac/datafile/undotbs1.260.722961083 
+DATADG/rac/datafile/sysaux.261.722961087 
+DATADG/rac/datafile/undotbs2.263.722961097 
+DATADG/rac/datafile/users.264.722961099 
+DATADG/rac/datafile/trans.270.728577593

1.4.8 DBMS_FILE_TRANSFER的可选性

从Oracle 10g开始,Oracle提供了DBMS_FILE_TRANSFER程序包,可以很方便地在本地数据库和远程数据库,ASM和文件系统间传输数据库文件。

有了DBMS_FILE_TRANSFER,数据库文件的传输就方便了许多,尤其是在传输基于ASM存储的数据文件时,不再局限于利用RMAN来进行传输,为我们提供了更多的选择。

注意,DBMS_FILE_TRANSFER具备一定的限制,单个数据库文件必须是512字节的整数倍,并且文件大小必须小于或者等于2TB,但是这基本上算不上什么弱点,我们的绝大多数需求都可以被满足。

DBMS_FILE_TRANSFER包一共包含了3个存储过程,分别提供本机之间拷贝(COPY_FILE)、本机从远程主机获取(GET_FILE)以及本机上传至远程主机(PUT_FILE)3种传输数据库文件的功能。

SQL> desc dbms_file_transfer 
PROCEDURE COPY_FILE 
 Argument Name         Type          In/Out Default? 
 ------------------------------ ----------------------- ------ -------- 
 SOURCE_DIRECTORY_OBJECT    VARCHAR2        IN 
 SOURCE_FILE_NAME        VARCHAR2        IN 
 DESTINATION_DIRECTORY_OBJECT  VARCHAR2        IN 
 DESTINATION_FILE_NAME     VARCHAR2        IN 
PROCEDURE GET_FILE 
 Argument Name         Type          In/Out Default? 
 ------------------------------ ----------------------- ------ -------- 
 SOURCE_DIRECTORY_OBJECT    VARCHAR2        IN 
 SOURCE_FILE_NAME        VARCHAR2        IN 
 SOURCE_DATABASE        VARCHAR2        IN 
 DESTINATION_DIRECTORY_OBJECT  VARCHAR2        IN 
 DESTINATION_FILE_NAME     VARCHAR2        IN 
PROCEDURE PUT_FILE 
 Argument Name         Type          In/Out Default? 
 ------------------------------ ----------------------- ------ -------- 
 SOURCE_DIRECTORY_OBJECT    VARCHAR2        IN 
 SOURCE_FILE_NAME        VARCHAR2        IN 
 DESTINATION_DIRECTORY_OBJECT  VARCHAR2        IN 
 DESTINATION_FILE_NAME     VARCHAR2        IN 
 DESTINATION_DATABASE      VARCHAR2        IN

以上过程的参数中,除了文件名称外,最关键的是DIRECTORY目录参数,这个目录需要预先设定,并且要求传输用户对相应的目录具有读或者写的权限。

看以下测试,首先通过asmcmd在DATADG下创建一个asmbk目录:

$ export ORACLE_SID=+ASM1 
$ asmcmd 
ASMCMD> ls 
DATADG/ 
FSHDG/ 
ASMCMD> cd DATADG 
ASMCMD> mkdir asmbk
然后在数据库内部创建两个DIRECTORY:

SQL> create directory ASMBK as '+DATADG/asmbk'; 
Directory created. 

SQL> create directory OBASE as '/opt/oracle'; 
Directory created. 
SQL> select * from dba_directories; 
OWNER   DIRECTORY_NAME         DIRECTORY_PATH 
---------- ------------------------------ -------------------------------------------------- 
SYS    ASMBK             +DATADG/asmbk 
SYS    OBASE             /opt/oracle

现在DBMS_FILE_TRANSFER就可以大显身手,快速地帮助我们解决文件传输的问题:

SQL> exec dbms_file_transfer.copy_file('OBASE','trans.dbf','ASMBK','trans.dbf'); 

PL/SQL procedure successfully completed.

看一下ASM磁盘组上的内容,实际上文件的位置是在DATAFILE下,asmbk下存放的是一个别名:

ASMCMD> ls 
DATADG/ 
FSHDG/ 
ASMCMD> cd DATADG 
ASMCMD> cd asmbk 
ASMCMD> ls 
trans.dbf 
ASMCMD> ls -l 
Type   Redund Striped Time      Sys Name 
                   N  trans.dbf => 
                     +DATADG/RAC/DATAFILE/COPY_FILE.271.728582605
DBMS_FILE_TRANSFER包更强大的功能是基于网络的远程PUT_FILE和COPY_FILE功能,这两个功能通过db link实现。以下是一个简单测试。

首先在远程数据库创建测试用户及目录,并进行授权:

SQL> create user eygle identified by eygle; 
SQL> grant connect,resource to eygle; 
SQL> create or replace directory OBASE as '/opt/oracle'; 
SQL> grant read,write on directory OBASE to eygle; 
SQL> grant execute on dbms_file_transfer to eygle;

接下来在本地数据库配置tnsnames.ora文件,并创建db link:

SMSDBN =
 (DESCRIPTION =
  (ADDRESS = (PROTOCOL = TCP)(HOST = 172.16.9.108)(PORT = 1521))
  (CONNECT_DATA =
   (SERVER = DEDICATED)
   (SERVICE_NAME = smsdbn)
  )
 ) 
SQL> create database link smsdbn connect to eygle identified by eygle using 'smsdbn';
Database link created.

SQL> select * from dual@smsdbn;
D
-
X

接下来就可以通过DB Link进行远程的文件操作了,PUT_FILE可以将文件传输至远程主机:

SQL> exec dbms_file_transfer.put_file( 
  'ASMBK','trans.dbf','OBASE','remote_trans.dbf','SMSDBN'); 

PL/SQL procedure successfully completed.

远程节点可以立刻检查到这个文件的存在:

SQL> ! ls -al remote_trans.dbf 
-rw-r-----  1 oracle  dba   10493952 Sep 1 17:16 remote_trans.dbf

进一步的,可以将远程文件读取到本地:

SQL> exec dbms_file_transfer.get_file( 
'OBASE','remote_trans.dbf','SMSDBN','ASMBK','local_trans.dbf'); 

PL/SQL procedure successfully completed.

本地ASM存储中,马上获得了这个文件:

$ export ORACLE_SID=+ASM1 
$ asmcmd 
ASMCMD> cd DATADG/ASMBK 
ASMCMD> ls 
local_trans.dbf 
trans.dbf 
ASMCMD> ls -l 
Type   Redund Striped Time   Sys Name 
                 N  local_trans.dbf => 
                    +DATADG/RAC/DATAFILE/FILE_TRANSFER.272.728586765 
                 N  trans.dbf => 
                    +DATADG/RAC/DATAFILE/COPY_FILE.271.728582605

而进一步的,将表空间置于热备模式下,可以通过DBMS_FILE_TRANSFER包将数据库热备到远程主机,甚至可以基于此来创建远程的Dataguard数据库,有时在数据库巨大,备份恢复空间不足时,通过这种方式进行数据传输与备库创建未尝不是一种妙解:

SQL> alter tablespace system begin backup; 
Tablespace altered. 

SQL> create or replace directory odata as '+DATADG/rac/datafile/'; 
Directory created. 

SQL> exec dbms_file_transfer.put_file( 
   'ODATA','system.259.722961061','OBASE','system01.dbf','SMSDBN'); 
PL/SQL procedure successfully completed.
SQL> alter tablespace system end backup;

Tablespace altered.

DBMS_FILE_TRANSFER为我们提供了多一个选择和灵活性,很多时候,Oracle一个小小的增强如果能够得到恰如其分的利用,就能够发挥巨大的优势。了解了Oracle的种种可能之后,我们才能够灵活运用,如臂使指。

1.4.9 用户的锁定

在Oracle Database 11g的创建脚本中,存在如下一个名为lockAccount.sql的脚本,该脚本在完成数据库创建之后,将部分用户账号锁定。一个简单的FOR循环完成了这个安全加固的工作:

SET VERIFY OFF 
set echo on 
spool D:\oracle\admin\eyglee\scripts\lockAccount.log append 
BEGIN 
 FOR item IN ( SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS IN ('OPEN', 'LOCKED', 'EXPIRED') AND USERNAME NOT IN ( 'SYS','SYSTEM') ) 
 LOOP 
 dbms_output.put_line('Locking and Expiring: ' || item.USERNAME); 
 execute immediate 'alter user ' || 
   sys.dbms_assert.enquote_name( 
   sys.dbms_assert.schema_name( 
   item.USERNAME),false) || ' password expire account lock' ; 
 END LOOP; 
END; 
/ 
spool off

1.4.10 最后的脚本
在完成了主要脚本的工作之后,剩下的是一些最后的维护工作。

这里还有两个脚本需要执行,首先执行的是postScripts.sql脚本,这个脚本主要对部分用户及部分数据库选件进行维护:

connect "SYS"/"&&sysPassword" as SYSDBA 
set echo on 
spool C:\oracle\admin\eygle\scripts\postScripts.log 
@C:\oracle\10.2.0\rdbms\admin\dbmssml.sql; 
execute dbms_datapump_utl.replace_default_dir; 
commit; 
connect "SYS"/"&&sysPassword" as SYSDBA 
alter session set current_schema=ORDSYS; 
@C:\oracle\10.2.0\ord\im\admin\ordlib.sql; 
alter session set current_schema=SYS; 
connect "SYS"/"&&sysPassword" as SYSDBA 
connect "SYS"/"&&sysPassword" as SYSDBA 
alter user CTXSYS account unlock identified by change_on_install; 
connect "CTXSYS"/"change_on_install" 
@C:\oracle\10.2.0\ctx\admin\defaults\dr0defdp.sql; 
@C:\oracle\10.2.0\ctx\admin\defaults\dr0defin.sql "SIMPLIFIED CHINESE"; 
connect "SYS"/"&&sysPassword" as SYSDBA 
execute dbms_swrf_internal.cleanup_database(cleanup_local => FALSE); 
commit; 
spool off

最后执行的脚本是postDBCreation.sql,在这个脚本中将创建spfile,解锁SYSMAN、DBSNMP用户,编译失效对象并配置DB Control:

connect "SYS"/"&&sysPassword" as SYSDBA 
set echo on 
spool C:\oracle\admin\eygle\scripts\postDBCreation.log 
connect "SYS"/"&&sysPassword" as SYSDBA 
set echo on 
create spfile='C:\oracle\10.2.0/dbs/spfileeygle.ora' 
FROM pfile='C:\oracle\admin\eygle\scripts\init.ora'; 
shutdown immediate; 
connect "SYS"/"&&sysPassword" as SYSDBA 
startup ; 
alter user SYSMAN identified by "&&sysmanPassword" account unlock; 
alter user DBSNMP identified by "&&dbsnmpPassword" account unlock; 
select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual; 
execute utl_recomp.recomp_serial(); 
select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual; 
host C:\oracle\10.2.0\bin\emca.bat -config dbcontrol db -silent -DB_UNIQUE_NAME eygle -PORT 1521 -EM_HOME C:\oracle\10.2.0 -LISTENER LISTENER -SERVICE_NAME eygle -SYS_PWD &&sysPassword -SID eygle -ORACLE_HOME C:\oracle\10.2.0 -DBSNMP_PWD &&dbsnmpPassword -HOST gqgai -LISTENER_OH C:\oracle\10.2.0 -LOG_FILE C:\oracle\admin\eygle\scripts\emConfig.log -SYSMAN_PWD &&sysmanPassword; 
spool C:\oracle\admin\eygle\scripts\postDBCreation.log 
exit;

看到在最后部分,通过emca.bat批处理文件,配置了DB Control,这里通过一条完整的命令快速地完成了DB Control的创建等工作,也可以通过手工方式对DB Control进行维护,关于这部分的内容请参考“第2章 从OEM到Grid Control”。

此外,需要注意的是以下几句命令:

select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual; 
execute utl_recomp.recomp_serial(); 
select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual;

在Oracle 9i的postDBCreation.sql的脚本中,这部分的内容如下:

@/opt/oracle/product/9.2.0/rdbms/admin/utlrp.sql;

其实两者是相同的,utlrp.sql中主体部分与Oracle 10g中是相同的:

@@utlrcmp.sql 
execute utl_recomp.recomp_serial(); 

Rem ===================================================================== 
Rem Run component validation procedure 
Rem ===================================================================== 

EXECUTE dbms_registry.validate_components;

Oracle在utlrp.sql脚本的注释中说得很明确:这是一个通用脚本,可以在任意时候运行,以重新编译数据库失效对象。

通常我们会在Oracle的升级指导中看到这个脚本,Oracle强烈推荐在migration / upgrade / downgrade之后,通过运行此脚本编译失效对象。但是注意,此脚本需要用SQL*Plus以SYSDBA身份运行,并且当时数据库中最好不要有活动事物或DDL操作,否则极容易导致死锁的出现。

这样使用模板创建数据库就完成了。

1.4.11 使用模板建库注意事项
当使用模板创建数据库时,有一点需要特别注意,那就是种子数据库的版本。因为种子数据库通常来自软件的初始分布版本,如安装Oracle Database 9.2.0,则种子数据库就是随软件发布的初始版本。如果我们安装了9.2.0再安装Patch 9.2.0.8,那么此后若使用模板种子数据库创建数据库,则数据库可能并不会自动升级为9.2.0.8的版本。

如此创建的数据库其BANNER显示为Oracle 9i Enterprise Edition Release 9.2.0.8.0:

SQL> select * from v$version; 
BANNER 
-------------------------------------------------------------------------------- 
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production 
PL/SQL Release 9.2.0.8.0 - Production 
CORE  9.2.0.8.0    Production 
TNS for 32-bit Windows: Version 9.2.0.8.0 - Production 
NLSRTL Version 9.2.0.8.0 - Production

而如果查询注册的组件会发现,大部分组件仍然是9.2.0.1的版本:

SQL> column comp_name format a35 
SQL> select comp_name, status, substr(version,1,10) as version from dba_registry; 
COMP_NAME              STATUS         VERSION 
----------------------------------- ---------------------- -------------------- 
Oracle9i Catalog Views       VALID         9.2.0.1.0 
Oracle9i Packages and Types     VALID         9.2.0.1.0 
Oracle Workspace Manager      VALID         9.2.0.1.0 
JServer JAVA Virtual Machine    VALID         9.2.0.1.0 
Oracle XDK for Java         VALID         9.2.0.2.0 
Oracle9i Java Packages       VALID         9.2.0.1.0 
Oracle interMedia          LOADED         9.2.0.1.0 
Spatial               LOADED         9.2.0.1.0 
Oracle Text             VALID         9.2.0.1.0 
Oracle XML Database         INVALID        9.2.0.1.0 
Oracle Ultra Search         VALID         9.2.0.1.0 
Oracle Data Mining         LOADED         9.2.0.1.0 
OLAP Analytic Workspace       LOADED         9.2.0.1.0 
Oracle OLAP API           LOADED         9.2.0.1.0 
OLAP Catalog            INVALID        9.2.0.1.0

已选择15行。
在这样的模式下运行,数据库的状况是不可靠的,在某些条件下,因为这些组件的不完备,可能会出现错误。在以上的数据库环境中,当drop用户时可能会遇到如下错误:

SQL> drop user eygle; 
drop user eygle 
* 
ERROR at line 1: 
ORA-01001: invalid cursor 
ORA-00600: internal error code, arguments: [qmxiUnpPacked2], [121], [], [], [],[], [], []

解决该问题的方法就是运行一个升级重要脚本catpatch.sql,按照以下步骤操作:

shutdown immediate
startup migrate
spool patch.log
@?/rdbms/admin/catpatch
spool off

之后可以查看patch.log日志文件来确认升级是否成功,如果成功完成,该日志末尾会显示相关组件版本:

DOC> END Component Patches */ 

COMP_NAME              STATUS   VERSION 
----------------------------------- ----------- -------------------- 
Oracle9i Catalog Views       VALID    9.2.0.8.0 
Oracle9i Packages and Types     VALID    9.2.0.8.0 
Oracle Workspace Manager      VALID    9.2.0.1.0 
JServer JAVA Virtual Machine    VALID    9.2.0.8.0 
Oracle XDK for Java         VALID    9.2.0.10.0 
Oracle9i Java Packages       VALID    9.2.0.8.0 
Oracle interMedia          VALID    9.2.0.8.0 
Spatial               VALID    9.2.0.8.0 
Oracle Text             VALID    9.2.0.8.0 
Oracle XML Database         VALID    9.2.0.8.0 
Oracle Ultra Search         VALID    9.2.0.8.0 
Oracle Data Mining         VALID    9.2.0.8.0 
OLAP Analytic Workspace       UPGRADED  9.2.0.8.0 
Oracle OLAP API           UPGRADED  9.2.0.8.0 
OLAP Catalog            VALID    9.2.0.8.0

所以在使用模板创建数据库时,一定要注意升级问题。

网友评论

登录后评论
0/500
评论
异步社区
+ 关注