数据泵(Data Pump)是Oracle 10g之后替代传统exp/imp的核心迁移工具,它通过DIRECT_PATH和EXTERNAL_TABLE两种方式搬数据,速度比老工具快得多。但在实际工作中,DBA拿到的dmp文件往往是整个数据库的导出,里面混杂了几十甚至上百个schema,而我们可能只需要其中的一两个。这时候如果全量导入,不仅浪费大量时间,还可能把目标库里已有的同名对象覆盖掉。本文就来详细讲解如何用impdp只导入指定的schema,以及各种相关的过滤和映射技巧。

一、使用SCHEMAS参数指定要导入的方案
impdp命令行中,SCHEMAS参数是最直接的过滤手段。假设源库导出时用的是full=y,dmp文件里包含了HR、SCOTT、OE等多个用户的数据,而我们只想要HR用户,那么命令可以这样写:
impdp system/password directory=DATA_PUMP_DIR \ dumpfile=full_exp.dmp logfile=imp_hr.log \ schemas=HR
这条命令会从dmp文件里只提取HR schema相关的所有对象,包括表、索引、触发器、存储过程、序列、授权等。有一点需要特别注意:impdp在处理SCHEMAS参数时,会先在目标库中检查该用户是否存在。如果HR用户在目标库里还没创建,导入就会直接报错ORA-39112之类的错误并跳过该方案。所以执行前要么提前手工建好用户并赋予 quota,要么在命令里加上transform=oid:n之类的参数,但更推荐的做法是提前创建:
-- 目标库提前创建用户并授权 CREATE USER hr IDENTIFIED BY hr123 DEFAULT TABLESPACE users QUOTA UNLIMITED ON users; GRANT CONNECT, RESOURCE TO hr;
另外一个细节是权限问题。执行导入的账户如果是system或具备IMP_FULL_DATABASE角色的账户,操作会顺利很多;如果用普通用户导入别人的schema,会因为没有权限操作不属于自己的对象而失败。这在生产环境里尤其要注意,很多权限最小化的账户在导数据时都会踩这个坑。
二、FROMUSER与REMAP_SCHEMA的区别和用法
不少从传统imp工具过渡过来的同学,习惯性地在impdp里写fromuser=HR,结果直接报参数不识别。这是因为impdp已经废弃了FROMUSER/TOUSER这对参数,改用REMAP_SCHEMA来实现类似的“换名导入”功能。两者的写法区别如下:
-- 传统imp的写法(impdp中已不支持) imp system/password file=exp.dmp fromuser=HR touser=HR_NEW -- 数据泵impdp的正确写法 impdp system/password directory=DATA_PUMP_DIR \ dumpfile=full_exp.dmp logfile=imp_hr_new.log \ remap_schema=HR:HR_NEW
REMAP_SCHEMA的含义是:把dmp文件中来自HR方案的所有对象,导入到目标库的HR_NEW方案下。使用它有几个隐含规则值得了解。第一,如果目标用户HR_NEW不存在,impdp会自动创建它,但自动创建的用户密码是随机的,表空间分配也可能不符合你的规划,所以最好还是提前手工建好。第二,REMAP_SCHEMA可以和SCHEMAS联合使用,先用SCHEMAS圈定源端范围,再用REMAP_SCHEMA改写目标方案名,这在多套环境共用一个dmp文件时非常实用:
impdp system/password directory=DATA_PUMP_DIR \ dumpfile=full_exp.dmp logfile=imp_comb.log \ schemas=HR,OE \ remap_schema=HR:TEST_HR \ remap_schema=OE:TEST_OE
第三点需要注意的是,REMAP_SCHEMA只改对象的归属方案,不会修改表空间。如果源端表存在独立的表空间,导入时通常还要配合remap_tablespace=OLD_TBS:NEW_TBS,否则可能出现目标库缺少对应表空间而报ORA-00959的错误。这两个参数搭配使用,才能完成一次干净彻底的schema级别迁移。
三、精细控制:跳过部分对象与只导数据不导结构
真实场景里,仅指定schema往往还不够。比如HR方案下有几百张表,我们只想导入其中一部分,或者只需要数据不需要索引、约束,impdp同样提供了对应的过滤参数。EXCLUDE和INCLUDE可以实现对象级别的增删筛选:
-- 排除掉大日志表和触发器,加快导入速度
impdp system/password directory=DATA_PUMP_DIR \
dumpfile=full_exp.dmp logfile=imp_filter.log \
schemas=HR \
exclude=TABLE:\"IN \('EMPLOYEES_LOG','AUDIT_BIG'\)\" \
exclude=TRIGGER
-- 只导入指定几张表的数据
impdp system/password directory=DATA_PUMP_DIR \
dumpfile=full_exp.dmp logfile=imp_inc.log \
schemas=HR \
include=TABLE:\"IN \('EMPLOYEES','DEPARTMENTS'\)\"
上面Linux环境下exclude的写法中,引号需要用反斜杠转义,这是很多人在shell里执行失败的原因。如果是在Windows的cmd或者写成parfile参数文件,转义规则又不一样。最稳妥的方式是把这些过滤条件写进parfile,避免shell转义的干扰:
-- imp_hr.par 参数文件内容
directory=DATA_PUMP_DIR
dumpfile=full_exp.dmp
logfile=imp_hr.log
schemas=HR
exclude=TABLE:"IN ('EMPLOYEES_LOG')"
content=DATA_ONLY
然后执行impdp system/password parfile=imp_hr.par即可。这里的content参数也值得一提,它有三个可选值:ALL表示结构和数据都导入(默认)、DATA_ONLY表示只导数据不建对象、METADATA_ONLY表示只建结构不导数据。在做表结构同步或者只刷新数据的场景下,合理使用content参数能省去大量二次清理工作。另外,如果担心索引和约束影响导入性能,可以用exclude=INDEX,CONSTRAINT先跳过,导完数据后再用METADATA_ONLY补建,这种分步策略在大表迁移时提速明显。
四、常见报错与排查思路
schema级别的导入最容易碰到的几类错误,提前了解能少走弯路。第一个是ORA-39002或ORA-39170,提示schema不可访问,通常是dmp文件里根本没有这个方案,可以先通过impdp ... sqlfile=check.sql把dmp里的DDL语句全部提取到文本文件里,确认目标schema是否存在以及它的对象清单,这个sqlfile参数是排查dmp内容的好帮手。
第二个常见问题是目录对象不存在,报ORA-39087。impdp必须通过directory对象访问文件,而不能直接写操作系统路径。如果不确定,可以用select * from dba_directories;查一下现有目录,或者让DBA执行CREATE DIRECTORY DATA_PUMP_DIR AS '/backup/dump';创建并授权读写。第三个是字符集和国家字符集不一致的警告,导日志里出现ORA-39355之类提示时数据可能被隐式转换,跨境迁移项目尤其要提前核对两端数据库的NLS参数。
最后建议养成两个习惯:一是每次导入都保留完整日志文件,出错时从第一个ORA错误开始看,后面的错误多半是连锁反应;二是正式导入前先用estimate_only=y估算一下数据量,或者用METADATA_ONLY试导一遍结构,确认对象清单符合预期后再执行真正的数据导入。这些小步骤花不了几分钟,却能避免在生产环境里反复回滚重来。