Oracle数据库导入导出工具选型指南:exp/imp与数据泵expdp/impdp实战
简介这是一款基于Java编写的Oracle数据库导入导出桌面工具面向数据库运维人员、开发工程师及对命令行操作不熟悉的技术用户用于解决数据迁移、备份恢复、离线分析等场景下的导入导出需求。压缩包共198个文件约45.31MB以68个dll、25个jar、24个properties、22个exe及字体、证书、配置等支持文件为主构成完整的Java运行与图形界面环境其中jre为程序运行所必需不建议删除。工具支持表空间、用户密码、数据文件路径、表或模式、压缩选项等参数设置并配套操作说明文档涵盖启动连接、参数配置、注意事项与常见错误处理。已有1985人学习下载。借助图形化界面读者可简化expdp、impdp及sqlplus等传统方式的操作流程同时了解分区策略、索引优化与分批导入等性能与安全实践提升Oracle数据库日常管理效率。1. Oracle 数据库导入导出工具从 exp/imp 到数据泵的选型与落地一次给客户做数据迁移源库是 11g目标库是 19c我图省事直接用了老 exp 导出结果 80GB 的表空间导到一半报错字符集还差点对不上。那次之后我才认真把 Oracle 数据库导入导出工具这条线捋清楚它到底分几代、什么场景用哪个、参数怎么设才不翻车。Oracle 的导入导出工具主要分两代老一代是 exp/imp新一代是数据泵 expdp/impdp两者不通用导出文件格式也不兼容。选错了工具轻则速度慢十倍重则直接报错中断。这篇面向的是需要做库间迁移、备份归档、部分表同步的 DBA 和后端工程师从工具选型讲到参数配置再到踩坑排查尽量让你照着就能跑通。2. 先搞清楚 exp/imp 和数据泵到底差在哪2.1 两代工具的底层机制差异exp/imp 是客户端工具导出时数据要经过客户端进程中转再写到文件。这意味着导出 100GB 数据客户端机器上会先落一份临时数据网络传输和磁盘 IO 都是瓶颈。数据泵 expdp/impdp 是服务端工具作业在数据库服务器上直接执行数据从数据文件读到目录对象指向的路径不经过客户端。这是两者性能差距的根本原因。另一个关键差异是并行能力。exp/imp 是单线程的一张大表只能一个进程慢慢导。数据泵支持 PARALLEL 参数可以开多个 worker 进程同时导出不同表甚至同一张表的不同分区。我实测过一张 200GB 的分区表exp 跑了将近 4 小时expdp 开 4 个并行度只用了 50 分钟。还有一点容易被忽略exp/imp 在 12c 之后虽然还能用但 Oracle 已经不再对它做功能增强很多新特性比如可传输表空间、压缩导出只有数据泵支持。如果你还在用 exp 做日常备份建议尽早切到数据泵。2.2 什么场景选哪个工具不是所有场景都无脑上数据泵。下面这张表是我自己总结的选型参考场景推荐工具理由跨版本迁移11g→19cexpdp/impdp支持版本兼容参数exp 高版本导低版本容易出问题单表快速导出exp 或 expdp小表 exp 更省事不用建目录对象全库备份归档expdp支持并行、压缩速度快客户端无服务器权限expexpdp 需要数据库目录对象权限部分数据按条件导出expdp支持 QUERY 参数exp 的 QUERY 限制多异构平台迁移数据泵可传输表空间exp 不支持跨平台字节序转换选型时还要注意一点expdp 导出的文件只能用 impdp 导入不能混用。我见过有人拿 expdp 导出的 .dmp 文件用 imp 去导直接报 not a valid export file。2.3 数据泵的核心组件目录对象和作业数据泵依赖两个东西DIRECTORY 对象和作业Job。DIRECTORY 是数据库里的一个逻辑名指向服务器文件系统上的一个真实路径。创建语法-- 创建目录对象指向服务器上的 /data/dump 路径 CREATE OR REPLACE DIRECTORY dpdir AS /data/dump; -- 授权给操作用户 GRANT READ, WRITE ON DIRECTORY dpdir TO scott;这里有个坑路径必须是数据库服务器上的路径不是你客户端机器的路径。很多人第一次用 expdp 会搞混这一点以为在自己电脑上建个目录就行。另外 Oracle 的目录对象名是大小写不敏感的但路径字符串是大小写敏感的Linux 下写错大小写会报 ORA-39002。作业是数据泵执行的最小单元。每次 expdp/impdp 调用都会在数据库里创建一个作业可以通过DBA_DATAPUMP_JOBS视图查看运行状态。作业名可以用 JOB_NAME 参数指定不指定的话 Oracle 自动生成一个类似 SYSTEM_EXPORT_FULL_01 的名字。作业运行期间如果中断可以用ATTACH参数重新挂上去看进度这个后面会细讲。3. expdp/impdp 实操从建目录到导入验证3.1 导出全库、按 Schema、按表三种模式数据泵导出有五种模式FULL、SCHEMA、TABLE、TABLESPACE、TRANSPORTABLE。日常用得最多的是前三种。全库导出# 全库导出开4个并行度压缩元数据和数据 expdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEfull_%U.dmp \ LOGFILEfull_exp.log \ FULLY \ PARALLEL4 \ COMPRESSIONALL \ JOB_NAMEfull_exp_job按 Schema 导出# 导出 scott 和 hr 两个 schema expdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEscott_hr_%U.dmp \ LOGFILEscott_hr_exp.log \ SCHEMASscott,hr \ PARALLEL2 \ COMPRESSIONALL按表导出# 导出 scott 下的 emp 和 dept 两张表 expdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEemp_dept.dmp \ LOGFILEemp_dept_exp.log \ TABLESscott.emp,scott.dept参数说明DUMPFILE里的%U是通配符当 PARALLEL 大于 1 时会自动生成多个文件比如 full_01.dmp、full_02.dmp。如果不写 %U 又开了并行Oracle 会报错。COMPRESSIONALL同时压缩数据和元数据能省 60% 到 80% 的空间但会消耗 CPUCPU 紧张的库可以只写COMPRESSIONDATA_ONLY或者不压缩。LOGFILE一定要指定不然日志会写到默认路径出问题不好找。3.2 导入REMAP_SCHEMA 和 REMAP_TABLESPACE 的用法导入最常见的需求是换 schema 名和换表空间。比如从测试库导出的 scott 用户数据要导入到生产库的 app 用户下# 导入时重映射 schema 和表空间 impdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEscott_hr_%U.dmp \ LOGFILEscott_hr_imp.log \ REMAP_SCHEMAscott:app \ REMAP_TABLESPACEusers:app_data \ PARALLEL4 \ TABLE_EXISTS_ACTIONSKIPREMAP_SCHEMAscott:app的意思是源 schema 的 scott 映射到目标的 app。可以写多组用逗号隔开。REMAP_TABLESPACE同理。TABLE_EXISTS_ACTION有四个值SKIP 跳过已存在的表APPEND 追加数据TRUNCATE 先清空再插入REPLACE 删表重建。生产环境我一般用 SKIP确认没问题再手动处理冲突表。导入前有个必做动作确认目标 schema 和表空间已经存在。impdp 不会自动建用户如果 app 用户不存在会报 ORA-39114。表空间也一样REMAP 的目标表空间必须提前建好。3.3 用 SQLFILE 参数先看 DDL 再决定导不导这是我最推荐的一个习惯导入前先用SQLFILE参数把 DDL 抽出来看一眼不实际执行导入。# 只生成 DDL 到 sql 文件不实际导入 impdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEscott_hr_%U.dmp \ SQLFILEpreview_ddl.sql \ REMAP_SCHEMAscott:app \ REMAP_TABLESPACEusers:app_data执行完去 dpdir 目录下看 preview_ddl.sql里面包含了所有 CREATE TABLE、CREATE INDEX、ALTER TABLE 语句。这样你能提前发现源库用了什么特殊数据类型、有没有分区表、索引建在哪个表空间、有没有 LOB 字段。我靠这个习惯躲过好几次翻车比如有一次发现源库用了自定义类型目标库没建提前补上了。3.4 查看作业进度和中断后重新挂载数据泵作业跑起来后想查进度有两个办法。一是看日志文件tail -f盯着。二是用交互模式 attach 到作业上# 交互模式 attach 到正在运行的作业 expdp system/passwordorcl ATTACHfull_exp_job进去之后可以敲STATUS看当前进度CONTINUE_CLIENT回到日志输出模式KILL_JOB杀掉作业。如果作业因为网络断开或者客户端退出而中断作业本身还在服务器上跑重新 attach 上去就行。但如果是KILL_JOB杀掉的作业就没了得重新导。有个细节attach 的时候如果作业已经跑完了会提示 Job is not running这时候去DBA_DATAPUMP_JOBS里查状态如果是 COMPLETED 就说明成功了看日志确认。4. 避坑与排查那些年我踩过的导入导出坑4.1 ORA-39002 和 ORA-39070目录对象路径问题现象执行 expdp 报 ORA-39002 invalid operation 和 ORA-39070 unable to open the log file。原因九成是目录对象指向的路径在服务器上不存在或者 Oracle 软件用户没有该路径的写权限。还有一种可能是路径写成了客户端路径。解决先登到数据库服务器上确认路径存在且 oracle 用户可写。用ls -ld /data/dump看权限必要时chmod 755或chown oracle:oinstall。然后查DBA_DIRECTORIES视图确认目录对象指向的路径对不对SELECT directory_name, directory_path FROM dba_directories WHERE directory_name DPDIR;4.2 字符集不一致导致中文乱码现象导入后中文变成问号或者乱码。原因源库和目标库的字符集不一致。exp/imp 时代这个问题很常见数据泵稍微好一点但也不是完全免疫。用NLS_CHARACTERSET查两个库的字符集SELECT parameter, value FROM nls_database_parameters WHERE parameter NLS_CHARACTERSET;解决如果源库是 ZHS16GBK目标库是 AL32UTF8导入时中文可能出问题。最稳妥的办法是导出前确认两边字符集一致不一致的话在导入时设置NLS_LANG环境变量匹配源库字符集。但注意NLS_LANG 只影响客户端显示不改变数据库实际存储。真正要改字符集得用 CSALTER 脚本风险很高建议在测试库先验证。4.3 导入时表空间不足报 ORA-01652现象impdp 跑到一半报 ORA-01652 unable to extend temp segment。原因目标表空间没有开自动扩展或者磁盘满了。数据泵导入时会先建表再插数据如果表空间不够建表就失败。解决导入前先估算源数据大小查源库的DBA_SEGMENTSSELECT owner, SUM(bytes)/1024/1024/1024 AS size_gb FROM dba_segments WHERE owner IN (SCOTT,HR) GROUP BY owner;然后确认目标表空间有足够空间或者加上DATAFILE ... AUTOEXTEND ON。临时表空间也要检查导入大表时排序操作会占用大量 temp。4.4 并行度开太高反而变慢现象PARALLEL8 导出结果比 PARALLEL2 还慢。原因并行度不是越高越好。每个 worker 进程都要消耗 CPU 和 IO如果服务器 CPU 核数不够或者磁盘 IO 到瓶颈了开太多并行反而互相抢资源。另外如果导出的表数量少但每张表很大并行度受限于表的数量多出来的 worker 是空闲的。解决并行度一般设为 CPU 核数的一半到三分之二。导出前看一眼服务器负载top和iostat都正常再开高并行。如果是单张大表可以考虑用PARTITION_OPTIONS按分区并行。4.5 导入后序列当前值不对现象导入完成后序列的 nextval 还是从 1 开始导致主键冲突。原因数据泵导入序列时默认只导入序列定义不导入当前值。除非导出时用了INCLUDESEQUENCE并且导入时没加EXCLUDE。解决导入后手动同步序列当前值。写个脚本批量处理-- 查询所有序列的当前值生成 ALTER 语句 SELECT ALTER SEQUENCE || sequence_owner || . || sequence_name || RESTART START WITH || last_number || ; FROM dba_sequences WHERE sequence_owner IN (APP);把生成的语句在目标库执行一遍。或者导出时加INCLUDESEQUENCE参数但注意这个参数在 11g 和 19c 的写法略有不同。5. 进阶技巧用 QUERY 和 INCLUDE 做精细化导出5.1 QUERY 参数按条件导出部分数据有时候不需要整张表只要某个时间段或者某个状态的数据。数据泵的QUERY参数可以做到# 只导出 emp 表中 deptno10 的数据 expdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEemp_dept10.dmp \ LOGFILEemp_dept10.log \ TABLESscott.emp \ QUERYscott.emp:\WHERE deptno10\注意 QUERY 的写法表名和条件之间用冒号分隔条件里的引号要转义。多个表可以写多个 QUERY 参数。这个参数在 exp 时代也有但 exp 的 QUERY 只能用于单表数据泵支持多表分别指定条件。有个限制QUERY 不能用于 FULL 模式只能用于 TABLE 或 SCHEMA 模式。另外如果条件里用了子查询性能可能很差因为数据泵是在服务端逐行过滤的。5.2 INCLUDE 和 EXCLUDE 控制对象类型默认情况下数据泵导出 schema 时会导出所有对象类型。但有时候你只想要表结构不想要数据或者只想要存储过程不想要表# 只导出表结构和索引不导数据 expdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEddl_only.dmp \ LOGFILEddl_only.log \ SCHEMASscott \ CONTENTMETADATA_ONLY \ INCLUDETABLE,INDEX # 排除某几张表 expdp system/passwordorcl \ DIRECTORYdpdir \ DUMPFILEexclude_tmp.dmp \ LOGFILEexclude_tmp.log \ SCHEMASscott \ EXCLUDETABLE:IN (TMP_LOG,TMP_DATA)CONTENT有三个值ALL 导数据和元数据DATA_ONLY 只导数据METADATA_ONLY 只导元数据。INCLUDE和EXCLUDE不能同时用会报错。INCLUDE 的语法是INCLUDE对象类型:条件对象类型可以是 TABLE、INDEX、PROCEDURE、FUNCTION、VIEW、SEQUENCE 等。5.3 用 PARFILE 管理复杂参数参数一多命令行就特别长容易写错。数据泵支持把参数写到一个文件里用PARFILE指定# parfile 内容示例exp_full.par DIRECTORYdpdir DUMPFILEfull_%U.dmp LOGFILEfull_exp.log FULLY PARALLEL4 COMPRESSIONALL JOB_NAMEfull_exp_job然后执行expdp system/passwordorcl PARFILEexp_full.parparfile 里每行一个参数不要写 expdp 命令本身。注释用 # 开头。这个方式特别适合把常用导出配置固化下来下次直接改几个值就能复用。5.4 验证导入结果的三个检查点导入完成后别急着收工至少做三个检查。第一对比源库和目标库的对象数量-- 源库执行 SELECT object_type, COUNT(*) FROM dba_objects WHERE ownerSCOTT GROUP BY object_type; -- 目标库执行同样的语句对比结果第二抽查几张关键表的行数SELECT EMP AS tab_name, COUNT(*) FROM scott.emp UNION ALL SELECT DEPT, COUNT(*) FROM scott.dept;第三检查无效对象SELECT object_name, object_type, status FROM dba_objects WHERE ownerAPP AND statusINVALID;如果有 INVALID 的存储过程或函数用ALTER PROCEDURE ... COMPILE重新编译。我一般还会跑一遍应用的核心查询确认数据能正常访问。5.5 一个我坚持了多年的习惯每次做导入导出不管多急我都会先在一个测试库上跑一遍完整流程。导出文件大小、导入耗时、报错信息全部记录下来。正式操作时对着记录走心里有底。另外导出文件至少保留两份一份在服务器上一份拷到异地。曾经有一次服务器磁盘故障导出文件全丢了只能从备份重来多花了整整一天。这些习惯看起来笨但关键时刻能救命。希望帮到你。本文还有配套的精品资源点击获取