尧图精选

Oracle exp/imp命令详解:逻辑备份与跨平台数据迁移实战指南

🕒 发布时间:2026/9/17 7:51:13 📁 来源:尧图网络
做过Oracle运维的人应该都曾被老前辈提醒“别小看exp/imp关键时刻能救命。”这句话我工作越久越认同。虽然Oracle 10g之后就主推数据泵expdp/impdp但传统exp/imp一直保留至今。一方面很多旧系统还在用9i、10g数据泵功能受限另一方面跨大版本、跨平台做逻辑迁移时exp/imp生成的dmp文件依然是最通用、最稳妥的中间载体。这篇文章把exp/imp的命令参数、执行模式、典型场景和常见坑完整梳理一遍适合正在做Oracle数据库备份迁移的DBA、运维工程师也适合刚入门、看到满屏报错不知道从何查起的同学直接照着用能少走很多弯路。1. exp/imp为何至今仍是“救命工具”适用场景与局限1.1 exp/imp的定位基于SQL的逻辑搬运理解exp/imp首先要把定位搞清楚。它和RMAN这类物理备份完全不是一回事。RMAN复制的是数据文件本身的物理块exp/imp则是把数据和元数据通过SQL层读取出来翻译成Oracle自定义的二进制格式写入后缀为.dmp的逻辑文件。导入时再反向执行把对象定义用DDL重建把行数据用INSERT一条条写回目标库。这一特性决定了它的核心卖点和操作系统平台无关。Windows上导出的dmp基本都能导入Linux上的Oracle只要字符集和版本兼容。这个“平台无关”是很多项目在迁移异构平台时宁可牺牲速度也坚持用exp/imp的主要原因。在进行小规模数据交付、第三方数据交换时一个dmp文件就是一套完整的schema比SQL脚本或CSV都要干净得多。另外要注意exp/imp是客户端工具通过SQL*Net连接到数据库实例。这意味着它不要求登录到数据库服务器本身只要客户端能网络连上实例就可以运行这是它相比数据泵的一个重要差异。数据泵虽然也有expdp客户端工具但大部分逻辑directory、dump文件都是在服务端处理网络模式还依赖dblink配置成本明显更高。我在很多网络隔离环境里部署过exp只要放通1521端口客户端装在Windows机器上就能直接导省事很多。1.2 什么情况下该老实回去用exp/imp我在项目中总结出exp/imp仍然有不可替代价值的四种场景老库搬迁源库是8i或9i没有expdp只能用exp。如果目标库版本也比较老exp/imp就是唯一选择。极小数据量数据交付有时甲方只要求导出几张表给第三方几张表加在一起几十MB用exp一条命令敲下去对方用imp就收了比expdp还要在服务端建directory来得简单。跨网络受限环境数据泵的dump文件默认落在数据库服务器文件系统拿到文件还得另走FTP或其他通道exp/imp可以将文件直接生成在客户端本地拷走文件即完成交付形式上更轻。带查询条件导出exp的query参数可以直接按where条件抽取数据历史版本的数据泵虽然也支持query但很多操作员不熟悉传统工具反而更顺手。但要承认它的局限首先是慢exp/imp是串行处理的大库动辄导出几小时、导入按天算与expdp的parallel并行差距悬殊二是不能跨版本向下兼容高版本导出的dmp低版本imp根本读不了三是对分区表、大对象、超长字段支持较弱稍不小心就触发一些老Bug。理解了这些你再遇到“为什么有人宁可用exp也不用expdp”的问题就不会觉得奇怪了。2. exp导出命令参数拆解从基本到进阶2.1 命令格式与三种连接方式exp的基本格式很容易记exp 用户名/密码[连接标识] 参数名参数值 [参数名参数值 ...]连接本地实例时可以不写。例如exp hr/hr file/tmp/hr.dmp通过网络连接则写全连接标识符可以是主机名、端口、服务名也可以是tnsnames.ora里定义的服务名exp hr/hr192.168.1.20:1521/orcl file/tmp/hr.dmp log/tmp/hr.log exp hr/hrORCL file/tmp/hr.dmp log/tmp/hr.log还有一种是交互式模式只输命令后回车Oracle会逐步提示输入用户名、缓冲区、文件、导出类型、是否导出表数据等。交互式适合刚上手的人但在脚本化运维中几乎没人用推荐一律用命令行或parfile参数文件方式可重复执行、可留痕。2.2 模式选择参数full、owner、tablesexp有三种模式分别是全库、用户、表对应三个参数fully全库模式要求执行者拥有EXP_FULL_DATABASE角色通常用sys或system账号执行导出整个数据库所有用户的对象、表数据、权限、角色等。ownerscott用户模式导出指定schema下的对象可以写多个用户用逗号分隔owner(scott,hr)。tables(emp,dept)表模式只导出指定表表名前可带用户前缀tables(hr.employees,hr.departments)。模式之间有个优先级问题如果同时指定多个模式参数exp会按照tables、owner、full的顺序处理以优先级最高的为准。日常运维中按用户导出是最常用的既避免全库导出的权限要求又能满足99%的业务迁移需求。我处理跨环境数据同步时绝大多数情况都是owner业务用户一条命令搞定。2.3 常用参数逐项详解我把高频参数整理成表格方便对照使用参数默认说明典型示例fileexpdat.dmp导出文件名可带绝对路径file/backup/data_20250101.dmplog无导出过程日志文件log/backup/data_20250101.logrowsy是否导出表数据设为n则只导结构rowsngrantsy是否导出对象授权grantsyindexesy是否导出索引定义indexesybuffer1024字节提取数据缓冲区大小单位字节buffer8388608directn是否使用直接路径导出directyquery无按查询条件导出表数据querywhere empno100consistentn是否使用一致性读导出consistentycompressn导入时是否将段压缩到一个区compressnstatisticsestimate导入时是否生成统计信息statisticsnonefeedback0每N行显示一次进度feedback10000parfile无参数文件路径避免命令行过长parfile/home/oracle/exp.partablespaces无按表空间模式导出tablespaces(users,ts2)真正要注意的往往是细节而不是参数本身。比如file和log我每次必写绝对路径防止命令在定时任务里执行时因为工作目录不对而把dmp文件写到奇怪的位置。log更是排错第一手资料丢了它几乎等于没有做过导出。2.4 细节陷阱buffer、direct、query和consistent先说话多的buffer。exp读取数据时默认缓冲区只有1KB速度慢且容易在遇到大对象时出问题。我一般习惯设成8MB或16MB即buffer8388608或buffer16777216。对于普通规模的表这个值能明显提升速度。但注意在directy直接路径模式下buffer参数不生效因为直接路径绕过了SQL执行层由服务器进程直接把数据写入dmp文件。directy适合导大表它不经过SQL命令处理效率高很多但有限制不能和query一起用。如果你既想按条件导出又想开directexp不会报错但query会被忽略导出来的是整表数据这是个很容易让人误踩的坑。另外direct模式对某些类型如LONG型的支持不如传统路径遇到报错需要切回directn重试。consistenty也是很多人搞不清的点。它的作用是让exp在一个统一的快照时间点读取数据确保导出过程中其他会话发起的DML不会造成表与表之间数据不一致。比如主表里删了1000行关联数据子表还没来得及删如果不用consistent导出时先导主表后导子表最终拿到的就是一个逻辑上互相矛盾的集合。这个参数会在导出期间额外占用undo表空间大库使用时要评估undo大小否则很容易触发ORA-01555快照过旧。还有一个老手习惯在走网络备份、且目标是支撑跨版本数据交付时我通常会在命令中加statisticsnone。不然exp默认会收集统计信息导致导入阶段大量时间浪费在计算统计信息上对于只为了搬数据的场景完全没有必要。3. imp导入命令参数拆解从基本到进阶3.1 imp的基本逻辑与连接方式imp的基本格式与exp对称imp 用户名/密码[连接标识] filexxx.dmp [fromuserxx touseryy] ...但导入有一个和导出非常不同的关键点导出时你用A账号导导入时却不一定要用A账号甚至强烈建议用目标库的sys/system账号来执行因为导入过程要创建表、索引、约束、触发器普通账号往往权限不够。连接方式同样支持本地、网络、交互式三种。交互式模式下会依次询问文件名、缓冲区、是否通过show仅显示DDL、是否导入整个文件、导入对象类型、是否导入数据、是否提交、是否忽略创建错误等。这些提示实际上就是在问你imp的命令行参数只是换成了向导式交互。理解每个问题背后的含义比死记命令参数更重要。3.2 核心参数逐项详解参数默认说明典型示例file无dmp文件路径必填file/backup/hr.dmpfromuser空从哪个用户导出的对象fromuserhrtouser空导入到哪个用户tousernewhrfulln是否全库导入fullytables空只导入指定表tables(employees,departments)ignoren对象存在时是否忽略创建错误继续ignoreyrowsy是否导入数据行rowsygrantsy是否导入授权grantsyindexesy是否导入索引indexesycommitn每条记录插入后是否提交commitybuffer30720字节插入数据缓冲区大小buffer8388608feedback0每N行显示进度feedback10000shown只显示导入内容不实际导入showyparfile无参数文件parfile/home/oracle/imp.parimp最有价值也最容易被用错的两个参数是fromuser和touser。它们负责实现“用户重映射”。3.3 fromuser/touser用户重映射与ignore/commit的取舍用过数据泵的人都知道expdp/impdp有REMAP_SCHEMA参数而传统imp实现用户映射靠的就是fromuser/touser。比如从生产库用ownerhr导出测试库上不存在hr用户想导入到test_hr用户imp命令可以这样写imp system/passwordtestdb file/backup/hr.dmp fromuserhr tousertest_hr rowsy buffer8388608 commity ignorey执行后原来属于hr用户的表、索引、约束全部落到test_hr用户下。注意fromuser的作用是告诉imp“这个dmp文件里哪些schema的对象我要拿”touser指定“放到哪个schema里”。如果只写fromuser不写touserimp会把对象导入到当前登录用户下或者尝试创建同名用户不同版本行为略有差别最稳妥的写法始终是两个参数成对出现。再来看ignore和commit。ignorey的意思是“如果对象已经存在跳过CREATE TABLE这类DDL报错继续尝试往表里插数据”。这种模式非常适合“目标库已有表结构、只想补数据”的场景。但隐患也很明显如果表结构定义不同会出现列不匹配、类型转换失败甚至插错列。所以我在生产上做完整导入时更推荐先drop掉同名用户或同名表用全新对象承载导入这样不需要ignorey也能顺利执行。commit推荐设为y因为默认n意味着整个导入过程只产生一个大事务一旦数据量庞大undo表空间和回滚段会非常吃力甚至直接报ORA-01555或ORA-30036。commity会在每行或每批插入后提交事务粒度小很多安全性更高。代价是导入速度略降因为每提交一次就要写一次redo。但对绝大多数场景来说稳定优先于速度。4. 实战演练从全库导出到按用户导入的完整流程4.1 环境准备与前置检查写代码之前先养成两个好习惯导出前查源库字符集导入前查目标库字符集并准备一个用来做“试导入”的临时用户。SELECT userenv(language) FROM dual;这一步很关键。导出机、源库、目标库的NLS_LANG设置不一致轻则导入后中文乱码重则数据长度超限报ORA-01461。标准的做法是让客户端NLS_LANG与源数据库字符集一致导出文件里才会正确记录字符信息。还要提前检查dmp文件大小预估。可以用exp向导估算也可以先小规模抽样比如导出一个大表和几个小表观察文件大小按比例推算。别等到导出两小时后才发现空间不够尤其是备份盘空间有限的生产环境这个检查能避免很多临时加班。4.2 全库导出命令示例假设源库是192.168.1.20:1521/orcl用system账号执行全库导出export NLS_LANGAMERICAN_AMERICA.ZHS16GBK exp system/oracle192.168.1.20:1521/orcl \ file/backup/full_exp_$(date %Y%m%d_%H%M%S).dmp \ log/backup/full_exp_$(date %Y%m%d_%H%M%S).log \ fully \ rowsy \ grantsy \ indexesy \ consistenty \ statisticsnone \ buffer16777216命令里每一行的含义fully全库导出rowsy保留数据grantsy和indexesy保证权限和索引不被丢掉consistenty保证时间点一致性statisticsnone省去统计信息buffer16777216是16MB加快读取。日志文件必须写后面排查问题全靠它。全库导出权限要求很高日志中如果出现IMP-00023或ORA-01031多半是当前账号没有EXP_FULL_DATABASE角色。解决办法是改用sys用户或给system授予这个角色GRANT EXP_FULL_DATABASE TO system;4.3 按用户导出的标准命令与典型坑生产环境里更常用的是按用户导出比如把业务用户apps整体搬出来exp system/oracle192.168.1.20:1521/orcl \ ownerapps \ file/backup/apps_$(date %Y%m%d_%H%M%S).dmp \ log/backup/apps_$(date %Y%m%d_%H%M%S).log \ buffer16777216 \ rowsy \ grantsy \ indexesy \ statisticsnone执行完再补一条ls -l /backup/apps_*.dmp看dmp文件大小和日志尾部是否显示“成功终止导出”。注意exp日志的最后一句话是“Export terminated successfully without warnings”如果看到“with warnings”甚至“with errors”一定要逐条查看警告内容。有些警告只是权限对象缺失但有些是数据截断。按用户导出最常见的坑是关联对象没有导全。比如apps用户下的很多表通过同义词访问shared用户下的数据ownerapps只会导出apps自己的对象同义词和权限也会导出但shared用户本身的表不包含在内。所以迁移时要把依赖链上的用户一起列出来owner(apps,shared,report)4.4 按表导出与快速推送如果只是给第三方推送少量数据按表导出更灵活exp system/oracle192.168.1.20:1521/orcl \ tables\(apps.orders,apps.order_items\) \ file/backup/orders_$(date %Y%m%d).dmp \ log/backup/orders_$(date %Y%m%d).log \ rowsy \ statisticsnone \ buffer8388608注意表名需要大写并且带schema前缀shell里括号和双引号要转义。这个命令在多数Linux shell下没问题但如果你用的是Windows命令行括号和引号的处理会有差异建议改用parfile参数文件方式避免转义问题# exp_params.par tables(apps.orders,apps.order_items) file/backup/orders_20250101.dmp log/backup/orders_20250101.log rowsy statisticsnone buffer8388608然后执行exp system/oracle192.168.1.20:1521/orcl parfile/home/oracle/exp_params.par4.5 导入到测试库的完整流程目标库导入时我喜欢先把现有同名用户清理干净避免一堆“对象已存在”的报错。假如导入目标是test库的business用户DROP USER business CASCADE; CREATE USER business IDENTIFIED BY business_pass DEFAULT TABLESPACE users QUOTA UNLIMITED ON users; GRANT CONNECT, RESOURCE TO business;然后执行导入imp system/passwordtestdb \ file/backup/business_20250101.dmp \ fromuserbusiness \ touserbusiness \ rowsy \ grantsy \ indexesy \ commity \ buffer16777216 \ log/backup/imp_business_20250101.log如果希望表都落到一个单独的表空间比如data_ts可以提前把目标用户默认表空间改到data_ts并在导入前确认所有表的TABLESPACE在目标库里不冲突。传统imp不支持REMAP_TABLESPACE所以合理规划默认表空间很重要。导入完成后用如下SQL快速做一致性校验SELECT COUNT(*) FROM business.orders; SELECT COUNT(*) FROM business.order_items;或者用imp日志末尾的“Import terminated successfully”来判断。但日志成功不代表数据一定对我曾遇到过索引和约束都建好了但某个大表实际行数比源库少几千行的诡异情况。原因出在目标库表结构定义与dmp不一致插入的一部分行被约束过滤或ignore参数跳过。所以凡是大迁移我都会在正式导入后再跑一遍“源库行数vs目标库行数”的对比脚本绝不只依赖日志。5. 踩坑实录字符集、权限、大表导出失败等高频问题5.1 字符集不一致一个低级却昂贵的错误这是exp/imp项目里出现频率最高的问题。典型场景是生产库字符集ZHS16GBK测试库字符集AL32UTF8客户端NLS_LANG没设置或设成AMERICAN_AMERICA.US7ASCII导入后中文全变成问号。正确的做法分两步。导出前在exp客户端的shell里设置与源库相同的NLS_LANGexport NLS_LANGAMERICAN_AMERICA.ZHS16GBK导入前在imp客户端的shell里设置与目标库相同的NLS_LANGexport NLS_LANGAMERICAN_AMERICA.AL32UTF8如果目标库和源库字符集不同且源库数据含中文建议先用字符集转换方案比如在导入dmp时用ALTER DATABASE CHARACTER SET需要停机或者采用CSSCAN工具检查再决定是否允许导入。不要想当然地认为“dmp文件反正跨平台通用”就自动无乱码实际上字符集不一致时乱码概率极高。另一个隐蔽问题是NLS_LANG设置正确但长度不够比如CLOB字段在AL32UTF8下每个中文字符占3字节原表字段设计时按ZHS16GBK估算长度写入时就会报ORA-01461“仅能绑定要插入到LONG列的LONG值”。这个错在imp日志里很容易被误判成数据问题实际上根源是字符集转换后字节长度超限。5.2 权限不足导致导入失败权限问题也是高频。最常见的报错是IMP-00031: must specify FULLY or provide FROMUSER/TOUSER arguments ORA-01031: insufficient privileges原因通常是当前用户没有IMP_FULL_DATABASE角色却又执行了fully或涉及其他schema的导入。解决办法GRANT IMP_FULL_DATABASE TO system;导入对象的原有授权如果希望通过grantsy一并带上还需要要求导入用户具有必要的权限否则部分索引如基于函数的索引会建不起来。生产实践中的基本规则是本地小范围导入用普通用户跨用户、全库级导入一律用system或sys。还有一类权限问题是导出时用户对表没有SELECT权限。比如A用户执行ownerB导出但A只有部分表的SELECT权限exp日志末尾会列出“EXP-00041: 用户B的某些表被跳过”。遇到这种情况要么先给A授予B的SELECT权限要么直接用具有EXP_FULL_DATABASE角色的账号导出。否则你拿到的dmp缺表缺数据后面发现问题时已经晚了。5.3 大表导出BUFFER、DIRECT与ORA-01555在大表上跑exp最容易遇见的报错是ORA-01555。根因有两个一是导出时间太长undo被后续事务不断覆盖导致读一致性快照失效二是consistenty开启后undo压力更大。解决思路分三步第一优先级把导出任务安排在业务低谷减少并发事务对undo的挤压。第二优先级适当调大undo表空间及保留时间比如临时加大UNDO_RETENTION。第三优先级调整exp参数增大buffer并考虑directy。如果表结构允许优先用directy绕过一致性读速度会快很多。如果大表实在太大建议拆表导出按季度或按分区导出多个dmp# exp_part.par tablesapps.orders querywhere order_date to_date(2024-01-01,yyyy-mm-dd) and order_date to_date(2024-04-01,yyyy-mm-dd) file/backup/orders_q1.dmp log/backup/orders_q1.log然后执行exp system/oracle192.168.1.20:1521/orcl parfile/home/oracle/exp_part.par注意query参数里单双引号在shell中的转义比较痛苦用parfile方式能避免大部分命令行转义问题也方便以后重复调整日期范围。5.4 老版本的LONG字段NULL丢失问题说到exp/imp的历史包袱最经典的是老版本特别是7.x、8i、9i在传统路径下导出含LONG或大字段的表时可能把空字符串或NULL值处理成错误数据。这种现象曾经让很多老DBA宁可反复做测试导出也不在生产上直接用默认参数。解决方法是理论与实践结合如果库里有LONG字段且必须用exp优先考虑directy模式或适当调大buffer并尽量在包含LONG字段的表上多做几次测试。更安全的选择是把LONG迁移为CLOB再走exp/imp流程。到了10g以后LONG字段问题已经很少见遇到类似报错时我会先查官方文档再决定是升级补丁还是改变导入策略。5.5 跨版本导入dmp文件新旧不兼容一个很容易忽略的规则是exp导出的dmp文件版本要和imp能够读取的版本匹配老版本exp生成的文件可以导入新版本imp但新版本exp生成的文件不能导入老版本imp。这就是为什么从11g导出、往9i导入基本必挂。判断方法也很简单用文本编辑器或者strings命令看dmp头部的版本信息常见错误有IMP-00010: 不是有效的导出文件头部验证失败 EXP-00008: 遇到无法识别的Oracle错误如果遇到高版本导出、低版本导入的需求一般只有三条路在低版本机器上直接exp低版本库如果数据源还是低版本把高版本库的数据导出后做版本转换或者干脆升级目标库。没有魔法版本兼容性是硬规则做迁移规划前一定要先确认版本。5.6 网络与监听故障ORA-12541、ORA-28547远程exp/imp时还会碰到连接层异常。ORA-12541表示监听器不可达或未启动常见于连接标识里的主机端口写错。ORA-28547和外部过程或异构服务代理相关多数出现在配置了HSHeterogeneous Services但执行代理程序路径错误时。这个错误不只是exp/imp会有但如果你用exp远程导出时遇到排查顺序是先tnsping连接串再查看监听状态最后检查sqlnet.ora里HS_FDS_CONNECT_INFO配置。网络问题的一个通用排查方法先在目标机器上用SQLPlus执行一条SELECT 1 FROM dual;确认连通性。SQLPlus能连上exp/imp大概率走上层逻辑就能通SQL*Plus都连不上别怀疑exp/imp先解决网络和监听。5.7 导入前清理目标对象的最佳实践很多新人导入时报一堆ORA-00942或ORA-01434就是因为目标库已经存在同名表imp默认在创建表阶段遇到“对象已存在”的错误后如果没有ignorey就直接中断。我有两种处理习惯如果允许清空目标schema先drop user xxx cascade再重建用户全新导入。这是最干净、最推荐的方式。如果只是补数保留原表但必须用ignorey同时提前用DELETE FROM 表名把测试数据清掉避免主键冲突导致大量插入失败。不管哪种方式都建议先拿一张小表做一次试导入摸清目标库的字符集、表空间、权限是否匹配再执行全量。这个试导入成本很低但能避免在生产变更窗口续期时才发现不可逆问题。最后分享一点我自己的操作习惯。我在现在的环境里保留了一套老脚本封装了好几个exp/imp的模版参数文件分别用于全库、单用户、单表三种模式。每次临时接一个“帮忙导个数据”的需求只需要改文件路径和用户名五秒钟就能出命令。经历过几次半夜加班修乱码、修权限的教训后我也养成了“导出必留日志、导入必跑行数校验”的铁律。如果你还在用exp/imp真心建议花十分钟把这套模版搭起来真的能少熬夜。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →