在前段時間,進行過一次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;