一次完整的expdp/impdp逻辑迁移

在前段时间,进行过一次expdp/impdp的逻辑迁移。但是也没有进行过非常详细的总结。这一次,终于想要把整个迁移过程和遇到的问题、解决方式都从头到尾的总结一下,用来以后给以后的迁移过程做个参考模板。

一、明确迁移目标:

本次迁移是通过expdp/impdp的方式,将业务用户数据用expdp导出到NFS上,然后再通过impdp导入到新数据库中。

二、主机存储操作

1.挂载NFS

将存储划分到其中1个节点,并制作为文件系统,然后将该文件系统通过NFS配置共享出去:

vi /etc/exports
#NFS server share directories
/share XXX.XXX.XXX.XXX/24(rw,insecure,no_root_squash,sync)
/share XXX.XXX.XXX.XXX/24(rw,insecure,no_root_squash,sync)
/share XXX.XXX.XXX.XXX/24(rw,insecure,no_root_squash,sync)

注:需要注意,这里将NFS的属性挂在为insecure,否则在导入的时候,可能会报错。

三、源端数据库调研:

1.确认需要迁移的用户

select username from dba_users where username not in ('ANONYMOUS','DBSNMP','EXFSYS','MDDATA','MGMT_VIEW','ORDPLUGINS','OUTLN','SCOTT','SI_INFORMATN_SCHEMA','SYSMAN','WK_TEST','WKPROXY','WKSYS','XDB','APPQOSSYS','AUDSYS','CTXSYS','DVSYS','GGSYS','LBACSYS','MDSYS','OJVMSYS','OLAPSYS','ORDSYS','SYS','SYS$UMF','SYSBACKUP','SYSDG','SYSKM','SYSRAC','SYSTEM','WMSYS','XS$NULL','DBSFWUSER','SI_INFORMTN_SCHEMA','DVF','GSMADMIN_INTERNAL','ORDDATA','GSMCATUSER','REMOTE_SCHEDULER_AGENT','PDBADMIN','GSMUSER','DIP','ORACLE_OCM','SPATIAL_CSW_ADMIN_USR','APEX_040200','APEX_PUBLIC_USER','SPATIAL_WFS_ADMIN_USR','user_impdp','FLOWS_FILES','APEX_050000') and owner not like '%APEX%';

2.查看是否有非系统表在系统表空间下

set line 999
col owner format a10
col segment_name format a30
col tablespace_name format a30
select owner,segment_name,segment_type,tablespace_name from dba_segments where owner not in ('ANONYMOUS','DBSNMP','EXFSYS','MDDATA','MGMT_VIEW','ORDPLUGINS','OUTLN','SCOTT','SI_INFORMATN_SCHEMA','SYSMAN','WK_TEST','WKPROXY','WKSYS','XDB','APPQOSSYS','AUDSYS','CTXSYS','DVSYS','GGSYS','LBACSYS','MDSYS','OJVMSYS','OLAPSYS','ORDSYS','SYS','SYS$UMF','SYSBACKUP','SYSDG','SYSKM','SYSRAC','SYSTEM','WMSYS','XS$NULL','DBSFWUSER','SI_INFORMTN_SCHEMA','DVF','GSMADMIN_INTERNAL','ORDDATA','GSMCATUSER','REMOTE_SCHEDULER_AGENT','PDBADMIN','GSMUSER','DIP','ORACLE_OCM','SPATIAL_CSW_ADMIN_USR','APEX_040200','APEX_PUBLIC_USER','SPATIAL_WFS_ADMIN_USR','user_impdp','FLOWS_FILES','APEX_050000') and owner not like '%APEX%';

注:如果存在业务数据存放在系统表空间下的,则需要先对这些表进行move操作,将表移出系统表空间,因为我们在迁移的时候是不会迁移系统表空间的,只能迁移业务表空间。

3.查看相应的表空间

select tablespace_name,sum(bytes)/1024/1024/1024 gb from dba_data_files where tablespace_name in
(select distinct tablespace_name from dba_segments where owner not in ('ANONYMOUS','DBSNMP','EXFSYS','MDDATA','MGMT_VIEW','ORDPLUGINS','OUTLN','SCOTT','SI_INFORMATN_SCHEMA','SYSMAN','WK_TEST','WKPROXY','WKSYS','XDB','APPQOSSYS','AUDSYS','CTXSYS','DVSYS','GGSYS','LBACSYS','MDSYS','OJVMSYS','OLAPSYS','ORDSYS','SYS','SYS$UMF','SYSBACKUP','SYSDG','SYSKM','SYSRAC','SYSTEM','WMSYS','XS$NULL','DBSFWUSER','SI_INFORMTN_SCHEMA','DVF','GSMADMIN_INTERNAL','ORDDATA','GSMCATUSER','REMOTE_SCHEDULER_AGENT','PDBADMIN','GSMUSER','DIP','ORACLE_OCM','SPATIAL_CSW_ADMIN_USR','APEX_040200','APEX_PUBLIC_USER','SPATIAL_WFS_ADMIN_USR','user_impdp','FLOWS_FILES','APEX_050000') and owner not like '%APEX%'group by tablespace_name;

四.创建表空间

1.根据业务实际要求,目标端创建表空间

create tablespace tablespace_name '+DISKGROUP_NAME' size 32767m autoextend off;
...
alter tablespace add tablespace_name add datafile '+DISKGROUP_NAME' size 32767m autoextend off;
...

2.查看临时表空间,目标端创建临时表空间

需要注意:,因为要导入索引,所以可能就会有业务用户的临时表空间需要使用:

select distinct tablespace_name from dba_temp_files;

create temporary tablespace TEMP_XXX tempfile '+DISKGROUP_NAME' size 32767m autoextend off;
...
alter tablespace  TEMP_XXX add tempfile='+DISKGROUP_NAME' size 32767m autoextend off;
...

五.查看源库是否有自己安装的组件,如果有,则需要在目标端安装:

col comp_id format a30
col comp_name format a40
col version format a40
select comp_id,comp_name,version from dba_registry;

六.在源端和目标端创建导出和导入用户,目录,授权:

如果用impdp+dblink,则直接在目标端创建即可,因为数据不用落地。这里,我们拿数据落地举例子。

源端:

创建用户:

create user user_impdp identified by oracle;
create directory dir_impdp as '/share/xxx';

赋权限:

根据现场赋权限,有些地方不能赋予dba权限,就赋予需要使用的权限

grant dba to user_impdp;
(grant connect,resource,unilimited tablespace to user_impdp)
grant read,write on directory dir_impdp to user_impdp;

目标端:

创建用户:

create user user_impdp identified by oracle;
create directory dir_impdp as '/share/xxx';

赋权限:

根据现场赋权限,有些地方不能赋予dba权限,就赋予需要使用的权限

grant dba to user_impdp;
(grant connect,resource,unilimited tablespace to user_impdp)
grant read,write on directory dir_impdp to user_impdp;

七.从源端导出全库数据

1.设置parfile:

vi expdp_full.par

directory=user_impdp
DUMPFILE=full_database_%U.dmp
LOGFILE=full_database.log
PARALLEL=32			 #根据cpu数量,设置并行
#version=11.2.0.4    #根据目标端要求来导出版本
SCHEMAS=AAA,BBB,CCC,DDD,EEE
#query=AAA.TABLE_1:"where 1=2"  #这种方式可以在引号中写条件,从而导出满足条件的内容,这里表示只导出表结构

2.导出数据

nohup expdp user_impdp/oracle PARFILE=expdp_full.par &

八.导入数据

1.创建用户parfile,方便导入使用

vi schema.par
schemas=AAAA,
BBBB,
CCCC,
DDDD,
EEEE

2.修改共享目录权限

chmod -R 777 /share

3.清除测试用户

操作前务必核对好机器,不要在生产库操作,且这步操作是在经历多次测试后才做的,新环境下不用做。

drop user AAAA cascade;
drop user BBBB cascade;
drop user CCCC cascade;
drop user DDDD cascade;
drop user EEEE cascade;

注:如果删除用户比较慢,则可以先删除其中的大表或者大对象后,在删除用户,就会很快。

4.导入profile

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=profile content=metadata_only logfile=impdp_profile.log &

5.导入角色

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=ROLE content=metadata_only logfile=impdp_role.log &

6.导入用户

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=USER,SYSTEM_GRANT,ROLE_GRANT,DEFAULT_ROLE parfile=schema.par content=metadata_only logfile=impdp_user.log &

7.导入元数据(只导入表结构)

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp exclude=type,package,user,index,trigger,procedure,CONSTRAINT,INDEX_STATISTICS,TABLE_STATISTICS parfile=schema.par content=metadata_only logfile=impdp_table.log &

8.导入数据

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp PARALLEL=32 parfile=schema.par content=data_only logfile=impdp_data_only.log &

9.重建索引:

重建索引分为两种方式:
1)通过impdp生成sqlfile,然后手动修改索引中的index的并行度,直接执行修改后的sqlfile,创建索引;

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=index sqlfile=index.sql parfile=schema.par content=metadata_only full=y logfile=create_index_sql.log &

修改sqlfile:

vi index.sql

create index AAA.index_1 on AAA.TABLE_1(COL_1) parallel 10;
alter index AAA.index_1 no parallel;
.... 

2)直接通过Impdp导入索引,同时加入parallel参数,对索引开启并行导入。

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=index parallel=32 parfile=schema.par content=metadata_only full=y logfile=create_index_sql.log &

两种导入的方式不同点在于:
通过sqlfile的方式,可以手动修改单独索引的parallel,从而加快单个索引的创建速度,但是创建索引还是逐个创建(当然,我们也可以通过手动对sqlfile进行分片,分成n个片,那么也可以等效为同时并行创建n个索引,且每个索引都是已parallel的并行度创建);
(12.2以后)直接通过impdp+parallel参数的方式,一条命令即可实现。且可以有parallel个索引同时创建,但是每个索引的创建,并不会使用并行。

10.重建约束:

对于约束,我们则可以直接通过impdp的方式直接导入,因为约束无法开启并行:

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=container parallel=32 content=metadata_only full=y logfile=create_constraint_sql.log &

而在12C以后,同样导入constraint,开启PARALLEL是会开启多个进程,同时导入多个constraint的,所以效率还是比较高。

在索引和约束导入过程中,需要注意以下几个问题,也是可以提前必坑的:
1)在导入索引后,发现索引的数量和原来的数量无法匹配上;
2)在创建约束的时候,发现有些约束会非常慢;
3)约束创建完以后,发现约束也有非常多的数量无法和源库匹配上;

对于问题一和问题二,我们可以生成约束的sql语句看一下约束创建语句:

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp include=container parallel=32 sqlfile=constraint.sql content=metadata_only full=y logfile=create_constraint_sql.log &

发现其中的constraint的创建方法,对于主键均是使用以下方式创建的:

alter table add constraint pk_xxxxx using (create unique index on table_name(col_1));

通过这种方式创建,数据库会先创建唯一索引,再增加约束,而在创建索引的时候,并不会开启并行,所以真正慢的地方不是导入约束,而是创建索引;同时,这些索引是不会在导入索引的时候生成到sqlfile中的,这也就解释了为什么在导入索引后,索引的数量与源端不一致(我们在导入这部分约束后,发现索引数量与源端完全一致);

对于问题三,导入约束后,对比发现目标端约束的数量远小于源端。
筛选几张表,对目标端和源端的表上的约束进行比对,发现在源端的约束中,有很多以SYS_开头的约束名字,但目标端却没有。

select * from dba_constraints;

这是因为,以SYS开头的约束,在创建的时候都没有指定约束名字,而在不同的系统中,没有指定名字的约束,数据库会自动给该约束生成一个SYS+编号名字。
对于这种约束,我们只能通过获取这些约束的DDL,并在目标库上执行才能成功创建。
具体方法如下:

select 
'select dbms_metadata.get_ddl('||''''||'CONSTRAINT'||''''||','||''''||CONSTRAINT_NAME||''''||','||''''||owner||''''||')'||' from dual;' 
from dba_constraints 
where owner='AAA' 
and CONSTRAINT_NAME like 'SYS%';

这样的约束大部分都是非空约束,所以执行起来还是比较快。

其实,从这里也可以看到,我们在应用程序开发的时候,开发标准的重要性:
1)如果我们创建主键约束的方式是先创建唯一索引,然后再通过唯一索引添加主键索引,那么索引则可以一次性全部创建好;
2)如果我们创建约束全部制定了名字,那么也可以一次性将约束全部导入,而不用单独创建。

11.最后导入除了统计信息以外的其他元数据(已经存在的会报错存在,并跳过)

nohup impdp user_impdp/[email protected]:1521/pdb directory=dir_impdp DUMPFILE=full_database_%U.dmp exclude=STATISTICS content=metadata_only logfile=impdp_metadata_last.log &

十.收集全库统计信息:

vi gather_static.sh

sqlplus / as sysdba<<EOF
alter session set container=pdb;
set timing on
alter system set resource_manager_plan = 'DEFAULT_PLAN' scope=both
exec dbms_stats.set_global_prefs('CONCURRENT','TRUE');
	begin
	dbms_stats.gather_database_stats(
	ESTIMATE_PERCENT=>DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'for all indexed columns', cascade=>true, degree=>120);
	end;
	/
exec dbms_stats.set_global_prefs('CONCURRENT','FALSE');
alter system set resource_manager_plan = 'FORCE:' scope=both
exit;
EOF

执行这个语句,收集全库统计信息:

nohup gather_static.sh &

十一.对比对象
这一步,分别对表、索引、约束、过程、触发器等数量进行比对即可。

select count(*) from dba_objects where owner not in ('ANONYMOUS','DBSNMP','EXFSYS','MDDATA','MGMT_VIEW','ORDPLUGINS','OUTLN','SCOTT','SI_INFORMATN_SCHEMA','SYSMAN','WK_TEST','WKPROXY','WKSYS','XDB','APPQOSSYS','AUDSYS','CTXSYS','DVSYS','GGSYS','LBACSYS','MDSYS','OJVMSYS','OLAPSYS','ORDSYS','SYS','SYS$UMF','SYSBACKUP','SYSDG','SYSKM','SYSRAC','SYSTEM','WMSYS','XS$NULL','DBSFWUSER','SI_INFORMTN_SCHEMA','DVF','GSMADMIN_INTERNAL','ORDDATA','GSMCATUSER','REMOTE_SCHEDULER_AGENT','PDBADMIN','GSMUSER','DIP','ORACLE_OCM','SPATIAL_CSW_ADMIN_USR','APEX_040200','APEX_PUBLIC_USER','SPATIAL_WFS_ADMIN_USR','user_impdp','FLOWS_FILES','APEX_050000') and owner not like '%APEX%') and object_type=&object_type;

猜你喜欢

转载自blog.csdn.net/wx370092877/article/details/106639756