今日实战主题:Linux系统Oracle服务器exp/imp数据生产迁移。作为一名数据库运维人,日常和数据迁移打交道是常态,但每一次实战都是一次经验沉淀。今天全程实操了从Linux系统Oracle服务器(192.168.31.56 crmdb file)到另一台Oracle服务器(192.168.31.58 fgwmsdb asm)的全量数据迁移,用exp导出、imp导入完成整个流程,全程踩坑不多但细节满满,特此记录下来,也给有需要的同行避坑~核心目标很明确:将源服务器上的全部数据通过Exp工具迁移到目标服务器,确保迁移后数据完整、可正常查询,无丢失、无异常。话不多说,开启今日的实战记录!一、先理清迁移核心流程(新手必看)
做事先理逻辑,数据迁移尤其如此,一步错可能就要返工。这次梳理的核心流程,亲测可用,整理成清晰步骤,方便后续复用:- 源端(Linux Oracle服务器)准备:创建用户、表空间,搭建测试表和测试数据,为迁移做基础铺垫;
- 源端本地执行Exp导出,将目标用户的数据导出为dmp备份文件,并生成日志记录导出详情;
- 目标端(异机)准备:创建与源端一致的表空间、用户及对应权限,避免导入时因对象缺失报错;
- 将源端导出的备份文件传输到目标端,确保文件完整无损坏;
- 目标端执行Imp导入,将备份文件中的数据导入到对应用户下;
- 双向验证:对比源端和目标端数据,确认数据量一致、对象有效,迁移成功。
看似简单的6步,每一步都有细节要注意,尤其是目标端的环境准备,少一个权限、表空间不一致,都会导致导入失败,这也是我之前踩过的坑,这次特意重点关注。二、实操环节:从环境准备到数据导出
实战的核心的就是落地,这一部分我会把关键操作步骤、命令逐一带出,都是可直接复制使用的实操指令,新手可以直接参考。(一)源端环境与数据准备
迁移前的准备工作是基础,必须确保源端有可迁移的数据,且环境配置无误。主要分为5个小步骤:先在源端创建两个表空间crm01data和crm02data,指定数据文件路径和大小,关闭自动扩展(根据实际需求调整,本次实战为固定大小):create tablespace crm01data datafile '/oradata/crmdb/crm011.dbf' size 300m autoextend off;create tablespace crm02data datafile '/oradata/crmdb/crm022.dbf' size 300m autoextend off;
创建对应用户crm01、crm02,指定默认表空间,授予DBA权限,并设置表空间配额无限制,确保用户有足够的操作权限:conn crm01/crm01@crmdb;create table crm01 (id number(30) primary key not null,name DATE);conn crm02/crm02@crmdb;create table crm02 (id number(30) primary key not null,name DATE);
分别用两个用户登录数据库,创建测试表,用于后续验证数据迁移的完整性:conn crm01/crm01@crmdb;create table crm01 (id number(30) primary key not null,name DATE);
为了模拟真实生产环境的数据量,创建两个存储过程,分别向两个测试表中插入10000条和20000条数据,插入完成后提交事务:-- crm01用户创建存储过程并执行conn crm01/crm01@crmdb;create or replace procedure p_crm01 isbeginexecute immediate 'select count(*) from crm01';for i in 1 ..10000 loopinsert into crm01(id,name) values(i,sysdate);commit;end loop;execute immediate 'select count(*) from crm01';end p_crm01;/beginp_crm01;end;/-- crm02用户创建存储过程并执行conn crm02/crm02@crmdb;create or replace procedure p_crm02 isbeginexecute immediate 'select count(*) from crm02';for i in 1 ..20000 loopinsert into crm02(id,name) values(i,sysdate);commit;end loop;execute immediate 'select count(*) from crm02';end p_crm02;/beginp_crm02;end;/
数据生成完成后,务必验证数据是否正常,确认数据量符合预期,避免带着错误数据进行迁移:-- 验证crm01表数据conn crm01/crm01@crmdb;select count(*) from crm01; -- 应返回10000select * from crm01 where id>9990; -- 查看末尾几条数据,确认插入正常-- 验证crm02表数据conn crm02/crm02@crmdb;select count(*) from crm02; -- 应返回20000select * from crm02 where id>19990; -- 查看末尾几条数据,确认插入正常
(二)源端Exp导出操作
数据准备无误后,开始执行导出操作。这里有个关键注意点:导出大表时,记得设置compress=n,避免导入时出现存储分配失败的问题(亲测踩过这个坑,特此提醒)。-- 1. 进入备份目录cd /backup-- 2. 执行exp导出,指定所有者、备份文件名、日志文件,设置缓冲区大小exp system/oracle owner=crm01,crm02 compress=n file=exp_u_crm01-$(date +%F.%s).dmp log=exp_u_crm01-$(date +%F.%s).log buffer=4096000-- 3. 将备份文件传输到目标服务器(192.168.31.58)cd /backupscp exp_u_crm01* 192.168.31.58:$PWD
导出完成后,一定要查看日志文件,确认导出过程无报错、数据量正常;传输文件后,也可以在目标端查看文件是否完整,避免传输过程中丢失。三、关键步骤:目标端导入前准备与导入操作
很多人迁移失败,都是栽在“目标端准备”这一步。导入前,必须确保目标端有与源端一致的表空间、用户和权限,否则会直接报错。这一步我做了详细的操作,确保万无一失。(一)目标端导入前准备
在源端执行脚本,生成表空间和用户权限的创建脚本,注意:此操作需在SQLPLUS中执行,PL/SQL中无法看到密码信息:spool crm_object_create_scripts.sqlSET SERVEROUTPUT ONSET LINESIZE 1000SET FEEDBACK OFFset long 999999SET PAGESIZE 1000-- 导出表空间创建语句SELECT DBMS_METADATA.GET_DDL('TABLESPACE', TS.tablespace_name)FROM DBA_TABLESPACES TS where TABLESPACE_NAME in ('CRM01DATA', 'CRM02DATA');-- 导出用户及权限创建语句set head offset pages 0set long 9999999SELECT DBMS_METADATA.GET_DDL('USER', USERNAME) || '/' DDLFROM DBA_USERS where username in ('CRM01', 'CRM02')UNION ALLSELECT DBMS_METADATA.GET_GRANTED_DDL('ROLE_GRANT', USERNAME) || '/' DDLFROM DBA_USERS where username in ('CRM01', 'CRM02')UNION ALLSELECT DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT', USERNAME) || '/' DDLFROM DBA_USERS where username in ('CRM01', 'CRM02')UNION ALLSELECT DBMS_METADATA.GET_DEPENDENT_DDL('OBJECT_GRANT', USERNAME) || '/' DDLFROM DBA_USERS where username in ('CRM01', 'CRM02');spool off;
将生成的脚本传输到目标端,查看脚本内容,根据目标端环境调整表空间数据文件路径(目标端为ASM存储,路径改为+dgdata01):-- 查看脚本内容cat crm_object_create_scripts.sql
sql-- 表空间创建(适配目标端ASM存储)CREATE TABLESPACE "CRM01DATA" DATAFILE '+dgdata01' SIZE 414572800 autoextend off;CREATE TABLESPACE "CRM02DATA" DATAFILE '+dgdata01' SIZE 414572800 autoextend off;-- 用户及权限创建(沿用源端密码信息,确保一致性)CREATE USER "CRM02" IDENTIFIED BY VALUES 'S:71380DF28BA189B012B407F5E1D410D9C75B4EE42CCB24FF7823C5B1533D;T:AACE4D5563CAAB9FBD021B88F3ED5D95BCC4FFA8278D60914044DC0C3D07806D01A0B78F6C9BF597C87A0D18F2142CAF8498B0A8012977C1E42A9112CC946CDEF93F6B5395753CFF4ACDAD18AFF2BE1F'DEFAULT TABLESPACE "CRM02DATA"TEMPORARY TABLESPACE "TEMP";CREATE USER "CRM01" IDENTIFIED BY VALUES 'S:3BA298DBB598FBA6280BD16E59757A1B0FE1520C61747E45638D1E98C4BB;T:1A5DB5406D0058F851E8820025C19A2C1537C480FD0C0B8242327E8DE1585FF58D6E0A5CFF92F1B4DE84044A5AC92AF9194DD8E5EA34D25D4481AF493B5BC8A11AACF3159339BB737D3BA99981D82630'DEFAULT TABLESPACE "CRM01DATA" TEMPORARY TABLESPACE "TEMP";GRANT "DBA" TO "CRM02";GRANT UNLIMITED TABLESPACE TO "CRM02";GRANT UNLIMITED TABLESPACE TO "CRM01";
执行调整后的脚本,在目标端创建好表空间、用户及权限,确保与源端一致。(二)目标端Imp导入操作
环境准备完成后,执行导入操作,指定源用户、目标用户、备份文件和日志文件,设置commit=y和ignore=y,避免因对象已存在导致导入失败:imp system/oracle fromuser=crm01,crm02 touser=crm01,crm02 file=exp_u_crm01-$(date +%F.%s).dmp log=exp_2table.$(date +%F.%s).log commit=y ignore=y buffer=4096000
导入过程中,建议实时查看日志文件,关注导入进度和是否有报错。如果出现权限不足、字符集不匹配等问题,及时排查(本次实战未出现此类问题,提前做好了环境适配)。四、收尾工作:数据验证与异常处理
导入完成不代表迁移成功,必须进行全面的验证,确保数据完整、对象有效。同时,针对可能出现的无效对象,做好后续处理。(一)数据合法性验证
1.数据量对比:查看exp和imp日志,确认导出、导入的数据量一致;同时在目标端查询表数据量,与源端对比:select count(*) from crm01.crm01; -- 应等于10000select count(*) from crm02.crm02; -- 应等于20000
2.对象有效性验证:检查目标端用户下的对象类型和数量,与源端一致;同时排查是否有失效对象: -- 查看对象数量select object_type s_object_type,count(*) from dba_objects where owner='CRM01' group by object_type ;select object_type t_object_type,count(*) from dba_objects where owner='CRM02' group by object_type ;-- 排查失效对象select * from dba_objects where status <> 'VALID' and owner='CRM01';select * from dba_objects where status <> 'VALID' and owner='CRM02';
3.跨库对比验证:通过dblink连接源端和目标端,直接对比对象数量,确保一致性:select s.s_object_type, s.s_count, t.t_object_type, t.t_countfrom (select object_type s_object_type, count(*) s_countfrom dba_objects@crmdbwhere owner = 'CRM01'group by object_type) s,(select object_type t_object_type, count(*) t_countfrom dba_objectswhere owner = 'CRM01'group by object_type) t;
(二)无效对象处理
如果验证过程中发现无效对象,可通过两种方式处理,按需选择:-- 1. 统计无效对象数量select owner,object_type,status,count(*) from dba_objects where status<> 'VALID' group by owner,object_type,status order by owner,object_type;-- 2. 生成编译SQLselect 'ALTER ' || OBJECT_TYPE || ' ' || OWNER || '.' || OBJECT_NAME|| ' COMPILE;' from dba_objects where status <> 'VALID' and object_type in('PACKAGE','PACKAGE BODY','FUNCTION','PROCEDURE','TRIGGER','VIEW') ;-- 3. 复制生成的SQL,手动执行编译
sqlplus / as sysdba@$ORACLE_HOME/rdbms/admin/utlrp.sql
(三)重新收集统计信息
迁移完成后,建议重新收集数据库或对应schema的统计信息,确保后续查询性能正常:-- 收集全库统计信息begindbms_stats.gather_database_stats;end;/-- 或收集指定schema统计信息beginDBMS_STATS.gather_schema_stats('CRM01');end;/beginDBMS_STATS.gather_schema_stats('CRM02');end;/
五、实战总结与避坑提醒
今天的exp/imp数据迁移实战,全程顺利完成,数据迁移后验证无误,可正常查询使用。结合本次实操和以往经验,整理了几个关键避坑点,分享给大家:- 导出时,大表务必设置compress=n,避免导入时存储分配失败;
- 导入前,目标端必须创建与源端一致的表空间、用户和权限,否则会直接报错;
- 导出、导入后,一定要查看日志文件,确认无报错、数据量一致;
- 迁移完成后,不仅要验证数据量,还要检查对象有效性,及时处理无效对象;
- 字符集和Oracle版本需一致,imp可导入低版本exp生成的文件,无法导入高版本文件,避免版本不兼容问题。
数据迁移看似简单,实则细节决定成败。每一次实操都是一次经验的积累,把这些细节记录下来,不仅方便自己后续复用,也希望能帮到正在做Oracle数据迁移的同行。后续会继续分享更多数据库运维实战案例,欢迎关注,一起交流学习、避坑成长~✨