1 传输表空间
异构跨平台传输表空间分为两种
- 使用MOS提供rman_xttconvert工具包进行在线迁移,即通常所说xtts。
- 表空间置为Read only离线,通过RMAN进行convert结合exp/imp expdp/impdp导出导入元数据进行迁移。
- 12c 引入了使用备份进行跨平台传输表空间,与上述第二种方法大部分步骤相同,RMAN备份方式可以充分利用RMAN压缩等降低文件大小,减少read only时间
2 版本介绍
- 源 端:HP-UX Oracle 11.2.0.3 ASM存储 数据量30TB
- 目标端:RHEL 7.7 Oracle 11.2.0.3 NAS存储
3 挂载NFS
源库30TB,HP-UX与Linux通过NFS挂载目标库NAS存储磁盘,直接convert转换数据文件至最终NAS存储,省去拷贝时间。
HP-UX
mount -F nfs hard,bg,proto=tcp,rsize=32768,wsize=32768,nointr,noac,forcedirectio,llock xx.xx.xx.xx:/data/nfs /tts
Linux:
mount -t nfs -o hard,bg,nolock xx.xx.xx.xx:/data/nfs /data
2.2 查询源端平台与目标平台是否可转换
select * from v$transportable_platform;
PLATFORM_ID PLATFORM_NAME ENDIAN_FORMAT
------------ ------------------------------------ --------------
...
4 HP-UX IA (64-bit) Big
...
13 Linux x86 64-bit Little
...--可以看到可以转换,但是由于字节序不同,所以需要转换。
select platform_id,platform_name from v$database;
PLATFORM_ID PLATFORM_NAME
------------ --------------------
4 HP-UX IA (64-bit)
3.迁移准备
3.1 提取需要转换的表空间
由于本次为整库迁移,所以除一些系统表空间外,其他均需要转换
- 查看system users sysaux是否有非sys以及一些组件对象
select owner
,table_name
,tablespace_name
from dba_tables
where owner not in ('SYS','SYSTEM','OUTLN','SCOTT')
and tablespace_name in ('SYSTEM','SYSAUX','USERS');
根据查询出来对象,决定是否需要额外处理这几个表空间,users表空间如果包含非sys对象,则需要在目标端删除users表空间,将源库users一起转换,本次查询users表空间也需要一同转换
- 获取需要迁移表空间列表
select distinct tablespace_name from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS2')
minus
select distinct tablespace_name from dba_temp_files;
3.2 验证要传输表空间是否自包含
SYS > EXEC SYS.DBMS_TTS.TRANSPORT_SET_CHECK(ts_list => '<TABLESPACE_NAME>', incl_constraints => TRUE);
SYS > SELECT * FROM TRANSPORT_SET_VIOLATIONS;
VIOLATIONS
--------------------------------------------------------------------
ORA-39921: Default Partition (Table) Tablespace xxx(表空间名) for xxx(表名) not contained in transportable set.
# 可以根据下满Mos文档进行相应处理
# 我的环境中,违反表空间不存在,也无相应segment在该表空间,根据表空间名称,创建之后,一起转换解决报错问题。Using Dbms_tts.transport_set_check Results in Entry in Transport_set_violations (Doc ID 114915.1)
3.3 表空间置为read only
select 'ALTER TABLESPACE '||TABLESPACE_NAME||' READ ONLY;'
FROM (
SELECT DISTINCT TABLESPACE_NAME FROM DBA_TABLESPACES WHERE TABLESPACE_NAME NOT IN ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS2')
MINUS
SELECT DISTINCT TABLESPACE_NAME FROM DBA_TEMP_FILES
)
置为read only过程中,遇到部分表空间无法read only,kill掉所有会话,但是依然无法read only,查询等待事件为wait for another txn - txn abort,
该等待一般为有状态处于dead状态事务,需要等待smon回滚结束,通过下面语句可以查询进度。
SELECT count(*) FROM x$ktuxe WHERE ktuxesta != 'INACTIVE' AND ktuxecfl LIKE '%DEAD%';
SELECT ktuxesiz FROM x$ktuxe WHERE ktuxesta != 'INACTIVE' AND ktuxecfl LIKE '%DEAD%';
4. 源库转换与元数据导出
4.1 rman convert转换
可以在远端convert tablespace,也可以在目标端convert datafile
#!/bin/sh
# rman convert script
export ORACLE_SID=
v_date=$(date +%Y%m%d%H%M%S)echo "Job Start time ${v_date}\n" >> rman_xtts_${v_date}.log
rman target / >> rman_xtts_${v_date}.log <<EOF
run{
allocate channel c1 type disk;
...
convert tablespace tbs1,tbs2... to platform 'Linux x86 64-bit' format '/rman/xtts/xtts_%U.dbf';
release channel c1;
...
}
EOF
v_end_date=$(date +%Y%m%d%H%M%S)
echo "Job End Time ${v_date}\n" >> rman_xtts_${v_date}.log
4.2 expdp导出元数据
$ nohup expdp system/111111 directory=xtts dumpfile=xtts.dmp parfile=expdp.par logfile=xtts_expdp.log &
$ vi expdp.par
TRANSPORT_TABLESPACES=tbs1
,tbs2
...
,tbsn
导出元数据时,expdp导出非常慢,查询相关文档,进行如下尝试:
- 尝试收集dictionary统计信息,并未提高效率。
- 根据下面文档,尝试使用非sysdba用户导出,效率有所提升。
Slow DataPump Import (IMPDP) For A Partitioned Table (Doc ID 2014960.1)
- 11.2.0.3版本有如下bug,需要打patch 13717234。
Bug 13717234 - Datapump export for transport is slow handling a large number of objects (Doc ID 13717234.8)
Transport Tablespace Expdp is Slow when Handling Large Number of Objects in the Database (Doc ID 1554570.1)
6. 目标库导入
6.1 impdp导入元数据与datafile
# 下面为测试环境示例,并非真实环境,真实环境只是使用路径与名称不同
$ impdp \'\/ as sysdba\' directory=xtts dumpfile=xtts.dmp parfile=xtts.par logfile=impdp_xtts.log$ vi xtts.par
TRANSPORT_DATAFILES=
(
'/rman/xtts/xtts_data_D-MESSAY_I-2399541070_TS-XTTS1_FNO-15_04vhgsno.dbf',
'/rman/xtts/xtts_data_D-MESSAY_I-2399541070_TS-XTTS_FNO-14_03vhgsnm.dbf',
'/rman/xtts/xtts_data_D-MESSAY_I-2399541070_TS-XTTS_FNO-8_02vhgsnl.dbf'
)Import: Release 11.2.0.4.0 - Production on Fri Jan 8 12:40:24 2021
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters, OLAP, Data Mining
and Real Application Testing options
Master table "SYS"."SYS_IMPORT_TRANSPORTABLE_01" successfully loaded/unloaded
Starting "SYS"."SYS_IMPORT_TRANSPORTABLE_01": "/******** AS SYSDBA" directory=xtts dumpfile=xtts.dmp parfile=xtts.par logfile=impdp_xtts.log
Processing object type TRANSPORTABLE_EXPORT/PLUGTS_BLK
Processing object type TRANSPORTABLE_EXPORT/TABLE
Processing object type TRANSPORTABLE_EXPORT/TABLE_STATISTICS
Processing object type TRANSPORTABLE_EXPORT/POST_INSTANCE/PLUGTS_BLK
Job "SYS"."SYS_IMPORT_TRANSPORTABLE_01" successfully completed at Fri Jan 8 12:40:34 2021 elapsed 0 00:00:08
6.2 表空间置为读写
SYS > alter tablespace tbs1 read write;
7. 目标库后续处理
7.1 目标库创建临时表空间
创建与源库相同表空间
# 源库查询是否使用临时表空间组
SQL > select * from DBA_TABLESPACE_GROUPS;
# 源库生成创建语句
SELECT 'create temporary tablespace '||TABLESPACE_NAME||' tempfile ''/path/'||tablespace_name||file_id||'.dbf'' size 32767M;' from dba_temp_files order by tablespace_name;
# 如果表空间有多个文件,还需要适当修改上述输出。
7.2 目标库赋权
# 源库获取用户列表
select username
from dba_users
where username not in ('SYS','SYSTEM','DBSNMP','OUTLN','ORACLE_OCM','XS$NULL','MDDATA','SPATIAL_UFS_ADMIN_USR','SPATIAL_CSW_ADMIN_USR','MGMT_VIEW','APEX_PUBLIC_USER') AND DEFAULT_TABLESPACE NOT IN ('SYSAUX');# 源库生成系统权限授权语句
#!/bin/sh
# sys privs generate script
for c in user1 user2
do
sqlplus -S system/oracle >> sys_priv_grants.log <<EOF
col PRIVILEGE for a30
col GRANTEE for a20
col ADMIN_OPT for a15
set lines 180
set pagesize 1000
set echo off
set heading off
set feedback off
SELECT 'GRANT '||a.PRIVILEGE||' TO '||'${c}'||';'
FROM
(
SELECT *
FROM DBA_SYS_PRIVS
WHERE GRANTEE = '${c}'
UNION ALL
SELECT *
FROM DBA_SYS_PRIVS
WHERE GRANTEE IN
(SELECT GRANTED_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTEE = '${c}' AND granted_role not in('EXP_FULL_DATABASE','IMP_FULL_DATABASE'))
) a;
exit;
EOF
done# 源库生成对象权限授权语句
#!/bin/sh
# tab privs generate script
for c in user1 user2
do
sqlplus -S system/oracle >> object_grants.log <<EOF
set lines 180
set pagesize 1000
set echo off
set heading off
set feedback off
col grantee for a15
col owner for a15
col table_name for a30
col grantor for a15
SELECT 'GRANT '||a.PRIVILEGE||' ON '||a.owner||'."'||a.table_name||'" TO '||'${c}'||';'
FROM
(
SELECT *
FROM DBA_TAB_PRIVS
WHERE GRANTEE = '${c}'
UNION ALL
SELECT *
FROM DBA_TAB_PRIVS
WHERE GRANTEE IN
(SELECT GRANTED_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTEE = '${c}' and granted_role not in('EXP_FULL_DATABASE','IMP_FULL_DATABASE'))
) a;
exit;
EOF
done
7.3 回收DBA权限
select 'revoke dba from '||username||';'
from dba_users
where username not in ('SYS','SYSTEM','DBSNMP','OUTLN','ORACLE_OCM','XS$NULL','MDDATA','SPATIAL_UFS_ADMIN_USR','SPATIAL_CSW_ADMIN_USR','MGMT_VIEW','APEX_PUBLIC_USER') AND DEFAULT_TABLESPACE NOT IN ('SYSAUX')
ORDER BY TEMPORARY_TABLESPACE;
7.4 目标库表空间置为读写
select 'ALTER TABLESPACE '||TABLESPACE_NAME||' READ WRITE;'
FROM (
SELECT DISTINCT TABLESPACE_NAME FROM DBA_TABLESPACES WHERE TABLESPACE_NAME NOT IN ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS2')
MINUS
SELECT DISTINCT TABLESPACE_NAME FROM DBA_TEMP_FILES
);SELECT TABLESPACE_NAME,STATUS FROM DBA_TABLESPACES;
7.5 全局临时表、db link 存储过程等对象处理
由于只转换了非system 、sysaux表空间,所以还需要单独导出业务用户除表、索引以外其他对象,例如序列、db link、全局临时表等,这些对象存储在system表空间数据字典。
--源端导出元数据
nohup expdp system/oracle directory=xtts parfile=expdp.par dumpfile=xtts_expdp_%U.dmp cluster=no logfile=xtts_expdp.log &
$ vi expdp.par
content=metadata_only
schemas=user1
,user2
...
,userN--目标端导入
--一些目录对象
nohup impdp system/oracle directory=xtts table_exists_action=append dumpfile=xtts_expdp_%U.dmp logfile=impdp_xtts.log &实际比对过程中,如下两部分有个别用户不同:
1.lob部分目标端缺失,经排查,此部分lob在源端也不属于任何表。
2.table partition部分目标端没有,经排查,部分回收站分区被统计,排除回收站名称分区 ,分区一致,开启recyclebin时,drop分区表之后,
dba_tab_partitions依然可以查询到删除的BIN开头的分区,https://www.eygle.com/archives/2017/04/drop_partition_recyclebin.html
7.6 数据比对
- 对象数量比对
-- 源端目标端均执行
-- 会生成user_object_count.log文件,源端目标端比对即可
-- 也可以采用下面比对行数方法创建oracle内部表进行比对
#!/bin/sh
# object count scripts
for c in user1 user2
do
sqlplus -S system/oracle >> users_object_count.log <<EOF
set echo off
set heading off
set lines 180
set pagesize 1000
SELECT DISTINCT OBJECT_TYPE,COUNT(*) FROM dba_objects where owner='${c}' GROUP BY OBJECT_TYPE ORDER BY 1;
exit;
EOF
done- 比对对象数量过程中遇到如下几个问题
1.table partition数量不一致,经排查,为源端drop了一部分分区表,drop的分区表在查询dba_tab_partitions时,依然可以查到分区,只不过名称都变成了BIN开头。
2.index partition数量不一致,也是由于上述原因,排除BIN$开头索引分区其余一致。
3.部分materialized view、view由于使用db link,而db link由于网络导致创建失败导致失效,后面需要手工迁移db link下面为批量获取源端db link ddl语句
--供参考
declare
v_objowner varchar2(50);
v_objname varchar2(50);
v_test clob;
cursor c is select owner,db_link from dba_db_links;
begin
open c;
loop
fetch c into v_objowner,v_objname;
if c%found then
execute immediate 'select dbms_metadata.get_ddl(''DB_LINK'''||','''||v_objname||''','''||v_objowner||''') from dual' into v_test;
dbms_output.put_line(v_test||';');
else
exit;
end if;
end loop;
close c;
end;
/4.目录对象
需要手工在目标端创建。
- 数据行数比对
-- 源端目标端均执行,然后可以将源库table_hash导入目标库通过语句校验。
-- 创建存储表数据量table_hash表
sqlplus -S system/oracle <<EOF
CREATE TABLE table_hash(owner varchar2(100),table_name varchar2(100),tc number,primary key(owner,table_name));
EXIT;
EOF-- 计算所有表数据量
for c in user1 user2
do
sqlplus -S system/oracle >> user_count.log <<EOF
DECLARE
v_cc number;
CURSOR v_tbl IS SELECT owner,table_name FROM dba_tables WHERE OWNER='${c}';
BEGIN
FOR c IN v_tbl LOOP
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM '||c.owner||'.'||'"'||c.table_name||'"' INTO v_cc;
INSERT INTO TABLE_HASH VALUES(c.owner,c.table_name,v_cc);
END LOOP;
COMMIT;
END;
/
EXIT;
EOF
done-- 校验
-- 可以在目标库创建源端db link进行比对
-- 也可以将源端比对数据表导入目标库进行比对
COL OWNER FOR A20
COL TABLE_NAME FOR A40
SET LINES 200 PAGES 2000
SELECT DEST.OWNER,DEST.TABLE_NAME,DEST.TC,SOURCE.TC
FROM TABLE_HASH DEST,
SOURCE.TABLE_HASH SOURCE
WHERE DEST.OWNER = SOURCE.OWNER
AND DEST.TABLE_NAME = SOURCE.TABLE_NAME
AND DEST.TC != SOURCE.TC;SELECT * FROM
SOURCE.TABLE_HASH SOURCE
MINUS
SELECT * FROM
TABLE_HASH DEST;--如果要计算hash值,计算绝对是否一致需要使用函数进行离线计算或者使用ogg veridata进行比对,SharePlex复制软件也有compare比对功能
7.7 目标库无效对象编译
SQL> EXEC UTL_RECOMP.recomp_parallel(4);
# 查询是否还有无效对象,再根据具体无效原因进行处理
SQL> select owner,object_type,object_name from dba_objects where status='INVALID';
7.8 收集统计信息
begin
dbms_stats.gather_database_stats(estimate_percent=>5,method_opt=>'for all columns size 1',degree=>16,cascade=>true,gather_sys=>true,gather_temp=>false,gather_fixed=>true);
end;
/begin
dbms_stats.gather_dictionary_stats(method_opt=>'for all columns size 1',degree=>16);
end;
/
7.9 根据源端调整数据库参数
根据源端参数相关设置,调整目标库参数设置。
7.10 修改弱密码
修改数据库内部以及操作系统弱密码符合安全要求。
8. 迁移过程遇到问题
expdp导出非常慢,中间尝试使用exp导出元数据
8.1 exp 使用tts传输表空间遇到报错
# 10g以后引入的分区技术,exp均不支持
EXP-00113: Feature New Composite Partitioning Method is unsupported,table will not be exported# 11g引入了Virtual Column与基于Virtual Column的分区技术
EXP-00107: Feature(VIRTUAL COLUMN) of column xxx in table xxx.xxx is not supported,table will not be exported# BINARY_DOUBLE BINARY_FLOAT为Oracle 10g引入的两种数据类型
EXP-00104: datatype (BINARY_DOUBLE) of column xxx in table xxx.xxx is not supported,table will not be exported
EXP-00104: datatype (BINARY_FLOAT) of column xxx in table xxx.xxx is not supported,table will not be exported
8.2 expdp导出缓慢
expdp导出数据缓慢,通过10046以及结合现象判断与下面两个问题高度关联
Slow DataPump Import (IMPDP) For A Partitioned Table (Doc ID 2014960.1)
# 解决方案: 需要使用非sysdba用户导出
Bug 13717234 - Datapump export for transport is slow handling a large number of objects (Doc ID 13717234.8)
Transport Tablespace Expdp is Slow when Handling Large Number of Objects in the Database (Doc ID 1554570.1)
# 解决方案:需要为11.2.0.3打补丁patch 13717234
8.3 一些元数据处理
- 由于我们迁移无法重启数据库,所以无法将数据库置为read only,如果可以将数据库置为read only,则直接可以在rman中convert database,无需convert tablespace转换。
- convert tablespace由于未传输system表空间,所以一些存放在数据字典中对象db link、目录对象需要手工创建。