在数据归档、备份、测试等场景,我们经常需要将数据从一个系统移动到另一个系统,一个较常用的方案是数据的导出/导入(export/import),但是在数据量较大的场景,此方案可能比较耗时。而可传输表空间是一种以文件为单位的数据移动技术,它绕过了导出/导入的数据处理过程,直接利用操作系统复制底层数据文件来快速移动数据。
使用export/import的方式来传输数据,在导出/导入时都需要解析数据内容,如果需要传输的数据比较大,那么这是一个非常耗时的过程。可传输表空间的思想就是通过绕过这个数据处理过程来提速。通过数据定义(元数据)和数据内容(业务数据)分离的方式,将数据内容通过文件拷贝(物理移动)来达到快速移动的目的。
由于可传输表空间底层是文件拷贝,因此它在兼容性上没有数据导出/导入广泛,在应用场景上有如下限制:
可传输表空间的过程分为下面4个步骤:
1. 将表空间置于只读状态
2. 导出元数据
3. 将表空间对应的数据文件及第2步导出的元数据文件拷贝到目标服务器
4. 在目标服务器导入元数据
在实际应用中,也可以专门建立一个表空间来使用这个特性。每次传输前将要传输的数据复制到这个表空间中,然后移动到目标系统,最后再加载到需要的表中。
先建立一个表空间和一张表作为示例数据:
create tablespace trans_tbs;
create table t(id integer) tablespace trans_tbs;
insert into t values(1);
commit;
在开始传输前,先检查表空间是否是自包含的,Oracle提供了dbms_tts.transport_set_check() 存储过程来检查,这个存储过程不会返回任何结果,是否冲突需要通过视图transport_set_violations查询:
exec dbms_tts.transport_set_check('TRANS_TBS', true);
Select * from transport_set_violations;
确定表空间是自包含的就可以移动数据了。
由于需要拷贝底层的数据文件,而在拷贝过程中不允许有事务对表空间进行修改,因此需要将表空间置于只读模式。这个要求对于OLTP系统可能有点苛刻,可以建立一个专门表空间专门进行数据传输,这样可以不影响正常业务的运行。
alter tablespace trans_tbs read only;
这里仅仅演示了一个表空间,如果同时传输多个表空间,只需要保证这些表空间是自包含的,并将它们置于只读即可。
元数据是指表空间中对象的定义数据,它们存在数据字典中,和表中的普通业务数据是分离。因此拷贝表空间文件不会包含元数据,元数据依然需要通过导出/导入的方式来移动。
下面的命令会在当前目录下生成名为trans_tbs.dmp的文件,transport_tablespace=y 选项意味着仅导出表空间的元数据,因此这个文件非常小:
exp userid=“/ as sysdba” transport_tablespace=y tablespaces=trans_tbs file=trans_tbs.dmp
表空间对应的数据文件路径可以用下面的命令查询,:
select tablespace_name, file_name from dba_data_files where tablespace_name='TRANS_TBS';
将表空间所包含的数据文件和第二步导出的元数据文件拷贝到目标系统,这里由于只有一个数据库,新建一个目录来模拟另一个系统:
mkdir /u01/app/oracle/oradata/PROD/PROD/datafile/trans_tbs
cp /u01/app/oracle/oradata/PROD/PROD/datafile/o1_mf_trans_tb_ljtf5d9p_.dbf /u01/app/oracle/oradata/PROD/PROD/datafile/trans_tbs/trans.dbf
完成数据文件的拷贝后,第一步中被设置为只读表空间就可以恢复读写状态了:
alter tablespace trans_tbs read write;
最后一步,仅需要将第二步导出的元数据在目标系统导入即可。这里由于是在同一个库演示,先将原表空间及文件删除,避免冲突:
drop tablespace trans_tbs including contents and datafiles;
使用imp命令导入元数据,这里需要提供要加载数据文件:
imp userid=\"/ as sysdba\" transport_tablespace=y tablespaces=trans_tbs file=trans_tbs.dmp datafiles=/u01/app/oracle/oradata/PROD/PROD/datafile/trans_tbs/trans.dbf
导入后再次查询dba_data_files表,可以看到表空间指向的是新数据文件,导入成功:
select tablespace_name, file_name from dba_data_files where tablespace_name='TRANS_TBS';
导入后的表空间是只读的,如果要更新,则要将其改为读写状态。如果只是用来迁移数据,可以采用直接路径插入insert /*+ append */ into … select …. 来将其快速加载到目标表中。