Oracle不支持直接迁移非CDB表空间到PDB,仅能通过可传输表空间(TTS)导入或整库转换为PDB两种方式实现;因数据文件头、容器ID、数据字典上下文等架构差异,直接拷贝会触发ORA-01122等错误。

不能直接迁移非CDB的表空间到PDB——Oracle不支持跨架构的表空间物理级挂载。你看到的“迁移表空间”,实际只有两条可行路径:要么把整个非CDB转换成PDB(即non-CDB to PDB),要么用可传输表空间(TTS)把目标表空间导出再导入到PDB中。前者是官方推荐的一次性升级动作,后者才是真正在PDB里“加表空间”的常规操作。
为什么不能直接拷贝非CDB的表空间文件到PDB?
非CDB的数据文件头里记录的是根容器(ROOT)级别的SCN和控制文件信息,而PDB有自己的数据字典、对象ID范围、undo表空间归属,且所有PDB共享CDB的控制文件和redo流。直接拷贝.dbf文件会导致ORA-01122、ORA-01207等“文件比控制文件新”类错误,数据库根本无法识别该文件属于哪个PDB。
- 非CDB没有
PDB$SEED或CDB$ROOT上下文,其数据字典视图(如dba_tables)指向全局obj$,而PDB内视图走的是本地容器对象映射 - 即使强行用
alter database create datafile重建,也无法修复file$、ts$、obj$之间的容器ID(con_id)一致性 - Oracle 19c明确禁止在
CREATE PLUGGABLE DATABASE语句中指定来自非CDB的datafile路径
正确做法:用可传输表空间(TTS)导入到已有PDB
这是最贴近“迁移表空间”需求的方案,适用于你已有一个运行中的PDB,只想把非CDB里的某几个表空间(比如USERS、APP_DATA)搬进去。前提是源非CDB和目标PDB字符集兼容、平台字节序一致(v$transportable_platform检查),且表空间为READ ONLY状态。
- 在非CDB中执行:
ALTER TABLESPACE app_data READ ONLY; - 用
expdp导出元数据:expdp '/ as sysdba' transport_tablespaces=app_data directory=dpump_dir dumpfile=tts_app.dmp - 拷贝
.dbf文件和tts_app.dmp到目标服务器(确保目标PDB所在CDB的db_create_file_dest可写) - 在目标PDB中执行
impdp:impdp '/ as sysdba' transport_datafiles='/u01/oradata/cdb1/pdb1/app_data01.dbf' directory=dpump_dir dumpfile=tts_app.dmp - 导入完成后,记得在PDB里执行:
ALTER TABLESPACE app_data READ WRITE;
更彻底的方案:把整个非CDB转成PDB
如果你打算长期使用多租户架构,且非CDB数据量不大(non-CDB to PDB转换是最干净的做法。它会把原非CDB整体“插”进CDB,变成一个独立PDB,原有表空间自动归属该PDB,无需手动拆分。
- 源非CDB必须先升级到12.2+(19c当然满足),并以
UPGRADE模式启动一次 - 执行
DBMS_PDB.DESCRIBE生成XML描述文件:exec DBMS_PDB.DESCRIBE(pdb_descr_file=>'/tmp/noncdb.xml', pdb_name=>'NONCDB2PDB'); - 在目标CDB中检查兼容性:
DBMS_PDB.CHECK_PLUG_COMPATIBILITY,重点关注PDB_PLUG_IN_VIOLATIONS视图里的ERROR级别条目 - 关键一步:创建PDB时必须用
USING子句引用XML,不能用FROM(那是远程克隆语法):CREATE PLUGGABLE DATABASE pdb_from_noncdb USING '/tmp/noncdb.xml' SOURCE_FILE_NAME_CONVERT=('/u01/oradata/noncdb/','/u01/oradata/cdb1/pdb_from_noncdb/') COPY FILE_NAME_CONVERT=('/u01/oradata/noncdb/','/u01/oradata/cdb1/pdb_from_noncdb/'); - 转换后PDB处于
MOUNTED状态,需手动ALTER PLUGGABLE DATABASE ... OPEN RESTRICTED,再运行$ORACLE_HOME/rdbms/admin/noncdb_to_pdb.sql脚本完成字典清理
真正容易被忽略的是字符集和时区处理:非CDB若用AL32UTF8,而目标CDB的CDB$ROOT是ZHS16GBK,即便DBMS_PDB.CHECK_PLUG_COMPATIBILITY返回YES,后续OPEN时仍可能卡在ORA-65139(数据库字符集不匹配)。务必提前用SELECT property_value FROM database_properties WHERE property_name = 'NLS_CHARACTERSET';两边核对。











