暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用模板创建数据库

原创 eygle 2019-09-05
1635

1.3  使用模板创建数据库


前面提到,除了定制数据库之外,还可以使用模板来创建数据库,接下来就让我们一起来了解一下使用模板创建数据库的过程。


1.3.1 启动创建


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


                                                           企业微信截图_15675866894837.png

                                                                                                                                       图1-20   DBCA 及其 快捷方式


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

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.3.2 数据库创建模板


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


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


                                           企业微信截图_15675867853256.png

                                                                                                                                             图1-22  选择模板


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


首先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


该脚本首先调用的是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.3.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.3.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.3.5传输表空间技术


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


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


                                                                                                         企业微信截图_1567587422143.png

                                                                                                                                         图1-22  是否包含示例方案

如果选择了包含示例方案,则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'";


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

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)。


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


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

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

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

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

¡  表在内部表空间集,而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.3.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


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 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 成功完成

 

5.  同字节序文件的跨平台


前面说过,当一个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

         10 Linux IA (32-bit)                         Little

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论