通过备份实现可传输表空间
Oracle8i 中引入的可传输表空间为实现更快的跨数据库数据传输提供了迫切需要的支持。使用此特性,您可以只导出表空间的元数据、传输数据文件并将转储文件导出到目标数据库主机以及导入元数据以将表空间“插入”到目标数据库中。该表空间中的数据在目标数据库中随即可用。该方法解决了数据仓库中曾一度存在的一个很棘手的问题:快速、高效地跨数据库移动数据。
但在 OLTP 数据库中,该条件通常是不可能存在的,因此传输表空间也是不可能的。如果 OLTP 数据库是数据仓库的数据源,则您可能始终无法使用可传输表空间加载它。
在 Oracle 数据库 10g 第 2 版中,可以传输表空间并从另一个数据源(即备份)中插入它。例如,如果要传输表空间 ACCDATA,则可以发出 RMAN 命令
RMAN> transport tablespace accdata 2> TABLESPACE DESTINATION = '/home/oracle' 3> auxiliary destination = '/home/oracle';
该命令在位置 /home/oracle 中创建一个辅助实例,并从其中的备份恢复文件。此辅助实例的名称是随机生成的。创建实例后,该过程将基于目录创建一个目录对象,并恢复表空间 ACCDATA(我们正在传输的表空间)的文件 - 所有操作均自动完成,您不必发出任何命令!
目录 /home/oracle 将包含表空间 ACCDATA 的所有数据文件、表空间元数据的转储文件以及脚本 impscrpt.sql(最重要的)。该脚本包含将此表空间插入目标表空间所必需的所有命令。该表空间并非由 impdp 命令进行传输,而是通过对 dbms_streams_tablespace_adm.attach_tablespaces 程序包的调用进行传输。可以在该脚本中找到所有必要的命令。
您可能会问,如果出现错误该怎么办?这种情况下,可以轻松地进行诊断。首先,该辅助实例在 $ORACLE_HOME/rdbms/log 中创建警报日志文件,以便您可以检查该日志以查明潜在的问题。其次,在提供 RMAN 命令时,您可以通过发出 RMAN 命令(该命令将所有输出置于文件 tts.log 中)将命令和输出重定向到日志文件
rman target=/ log=tts.log
然后,您便可以检查该文件来查明故障的确切原因。
最后,将把这些文件恢复到 /home/oracle 的 TSPITR_
长期以来,DBA 一直期待着能够通过 RMAN 备份创建一个可传输的表空间。但请注意,您是从备份(而不是从联机表空间)中插入传输的表空间。因此,它将不是最新的。
对已分区的按索引组织的表实现快速的分区分割
考虑这样一种情况:假设您拥有一个已分区的表。月末到了,但您忘了为下一个月定义分区。您现在有哪些选择呢?
您唯一的救济方法就是将最大值分区分割为两个部分:一个用于新月份的分区和一个新的最大值分区。但将该方法用于已分区的按索引组织的表时将遇到一个小问题。这种情况下,将先创建物理分区,并将行从最大值分区移动到该分区,这样将消耗 I/O 和 CPU 周期。
在 Oracle 数据库 10g 第 2 版中,该过程得到显著简化。如下图所示,假设您将分区一直定义到 5 月份,然后已经将 PMAX 分区定义为一个通用分区。由于 6 月份没有特定分区,因此 6 月份数据进入 PMAX 分区。灰显的方框显示了填充到该段中的数据。由于只填充了部分 PMAX 分区,因此您只看到一部分灰色区域。
现在,在 6 月 30 日对分区 PMAX 进行分割,以创建 6 月分区和新的 PMAX 分区。由于当前 PMAX 中的所有数据都将进入新的 6 月分区,因此 Oracle 数据库 10g 第 2 版只创建新的最大值分区,并使现有分区成为新创建的月分区。这就导致了根本不会发生数据移动(因此没有“空”的 I/O 和 CPU 周期)。而最好之处在于,ROWID 不会发生变化。
通过联机重新定义将 LONG 转换为 LOB
如果数据仓库数据库已经存在一段时间,并且您要处理大型文本数据,则您可能拥有大量数据类型为 LONG 的列。毋庸质疑,LONG 数据类型在大多数数据操作环境(如通过 SUBSTR 进行搜索)中是没有用处的。您肯定需要将它们转换为 LOB 列。
可以使用 DBMS_REDEFINITION 程序包联机执行该操作。但在 Oracle 数据库 10g 第 2 之前,有一个很大的限制。
将 LONG 列转换为 LOB 列时,您很希望获得高性能;您需要使该过程尽可能地快。如果将表进行了分区,则该过程将跨分区并行执行。但如果未将表进行分区,则该过程将串行执行,从而可能持续很长时间。
幸好,在 Oracle 数据库 10g 第 2 版中,即使表未分区也可以在 DBMS_REDEFINITION 程序包内部执行从 LONG 到 LOB 的联机转换。我们通过一个示例来了解该转换的过程。以下是一个用于保存发送给客户的电子邮件的表。由于邮件正文(存储在 MESG_TEXT 中)通常是较长的文本数据,因此已将该列定义为 LONG。
SQL> desc acc_mesg Name Null?Type ----------------------------------------- -------- --------- ACC_NO NOT NULL NUMBER MESG_DT NOT NULL DATE MESG_TEXT LONG
您需要将该列转换为 CLOB。首先,创建一个结构相同的(最后一列除外,它被定义为 CLOB)空临时表。
create table ACC_MESG_INT ( acc_no number, mesg_dt date, mesg_text clob );
现在,启动重新定义过程。
1 begin 2 dbms_redefinition.start_redef_table ( 3 UNAME => 'ARUP', 4 ORIG_TABLE => 'ACC_MESG', 5 INT_TABLE => 'ACC_MESG_INT', 6 COL_MAPPING => 'acc_no acc_no, mesg_dt mesg_dt, to_lob(MESG_TEXT) MESG_TEXT' 7 ); 8* end;
注意第 6 行,该行已经对列进行了映射。前两列保持不变,但第三列 MESG_TEXT 已被映射,以便通过对源表的列应用函数 TO_LOB 来填充目标表的 MESG_TEXT 列。
如果要重新定义的表很大,则需要定期对源表和目标表之间的数据进行同步。该方法加快了最终同步的速度。
begin dbms_redefinition.sync_interim_table( uname => 'ARUP', orig_table => 'ACC_MESG', int_table => 'ACC_MESG_INT' ); end; /
根据表的大小,您可能需要多次执行以上命令。最后,使用以下代码完成重新定义过程
begin dbms_redefinition.finish_redef_table ( UNAME => 'ARUP', ORIG_TABLE => 'ACC_MESG', INT_TABLE => 'ACC_MESG_INT' ); end; /表 ACC_MESG 已经发生了变化:
SQL> desc acc_mesg Name Null?Type ----------------------------------------- -------- --------- ACC_NO NOT NULL NUMBER MESG_DT NOT NULL DATE MESG_TEXT
注意,MESG_TEXT 列现在为 CLOB 而非 LONG。
该特性对于将错误定义的数据结构或原先遗留的数据结构转换为更容易管理的数据类型非常有用。