梁铭图,新炬网络首席架构师。具有十余年数据库运维、数据库设计、数据治理以及系统规划建设经验,拥有Oracle OCM和ACE Director、Togaf企业架构师(鉴定级)、IBM CATE等认证,曾获dbaplus年度MVP、华为云MVP等荣誉,并参与数据资产管理国家标准的编写工作。在数据库运维管理和架构设计、运维体系规划、数据资产管理方面有深入研究。
背景
Oracle 11g已经进入产品生命周期的尽头,我们的客户中使用Oracle 11g的中古系统还是挺多。为避免出现bug或其他问题时得不到Oracle官方的支持,近年来有大量的系统陆续迁移到19C的环境中。之前,在一些线上的分享中我谈得使用GoldenGate进行迁移,这里我们主要描述另一种常用的方式XTTS(Cross-Platform transport tablespace)。
迁移环境
本次迁移环境如下:
源数据库版本 11.2.0.4
源操作系统 HPUX
目标数据库 19.5
目标操作系统 linux
迁移实施
XTTS 实际上是 TTS 的增强功能。TTS 意为传输表空间,原理是将业务表空间从一个库传到另一个库,以达到数据迁移的目的。XTTS 则可以支持跨平台字节格式、增量进行传输。(跨平台传输表空间仅支持 oracle 11g 或以上)。它的主要实施步骤包括:
1)迁移前检查
检查无效index
select owner, index_name, status from dba_indexes
where status='UNUSABLE' order by 1,2;
select i.owner, i.index_name, p.partition_name, p.status
from dba_ind_partitions p,dba_indexes i
where p.index_name=i.index_name and p.status='UNUSABLE'
order by 1,2,3;
select i.owner,i.index_name,s.subpartition_name,s.status from
dba_ind_subpartitions s,dba_indexes i where
s.index_name=i.index_name and s.status='UNUSABLE'
order by 1,2,3;
检查是否有无效对象
select owner,object_type ,STATUS,count(*)
from dba_objects
where status != 'VALID'
group by owner,object_type ,STATUS;
select object_name,owner ,last_ddl_time from dba_objects where status='INVALID';
检查是否有外部表
SQL> select distinct owner from DBA_EXTERNAL_TABLES;
IOT表检查
select distinct owner from dba_tables where IOT_TYPE is not null;
检查临时表
SELECT owner,table_name FROM DBA_TABLES WHERE TEMPORARY='Y' AND OWNER IN(用户列表);
物化视图检查
select owner,count(*) from dba_mviews group by owner;
表空间是否自包含
SQL> EXEC sys.dbms_tts.transport_set_check('需要迁移的表空间列表',TRUE);
select * from transport_set_violations;
表空间是否加密
select tablespace_name,ENCRYPTED from dba_tablespaces;
表空间字段是否加密
select * from DBA_ENCRYPTED_COLUMNS;
检查表空间是否包含XML Types
select distinct p.tablespace_name from dba_tablespaces p,
dba_xml_tables x, dba_users u, all_all_tables t where
t.table_name=x.table_name and t.tablespace_name=p.tablespace_name
and x.owner=u.username;
select distinct p.tablespace_name
from dba_tablespaces p,
dba_xml_tab_cols x,
dba_users u,
all_all_tables t
where t.table_name=x.table_name
and t.tablespace_name=p.tablespace_name
and x.owner=u.username;
2)Xtts配置
在新环境中比对并创建角色
select 'create role '||role ||';' from dba_roles@XTTS_DBLINK
minus
select 'create role '||role ||';' from dba_roles;
在新环境中比对并创建用户
select 'create user "'||a.username ||'" identified by values '''||b.password||
''' default tablespace USERS '|| 'temporary tablespace '||
a.TEMPORARY_TABLESPACE||';'
from dba_users@XTTS_DBLINK a,sys.user$@XTTS_DBLINK b,
dba_users c,sys.user$ d
where a.username=b.name and
a.username=d.name(+)
and a.username = c.username(+) and c.username is null
order by a.username;
在新环境中创建profile
Select 'create profile '||distinct profile||';' from dba_profiles@XTTS_DBLINK minus
select 'create profile '||distinct profile ||';' from dba_profiles;
生成恢复用户默认表空间和临时表空间的脚本
set pagesize 100
set line 200
spool user_default.sql
select 'alter user '||username||' default tablespace '||default_tablespace||' temporary tablespace '||temporary_tablespace||';' from dba_users order by username;
spool off
创建非默认临时表空间
select tablespace_name,status,sum(bytes)/1024/1024 temp_size_mb from dba_temp_files group by tablespace_name,STATUS;
新旧环境网络配置文件检查
在新旧环境中对比listener.ora、tnsnames.ora和sqlnet.ora文件,需保持一致。
--提前检查,环境搭建过程中应创建
待确认
生成为应用用户赋对象权限脚本
set head off
spool tts_sys_privs.sql
-- Grant Table privileges
select 'grant '||privilege||' on "'||
owner||'"."'||table_name||'" to "'||grantee||'"'||
decode(grantable,'YES',' with grant option ')||
decode(hierarchy,'YES',' with hierarchy option ')||';'
from dba_tab_privs a
where owner in
(select name
from system.logstdby$skip_support
where action=0)
and grantee in
(select username
from dba_users
where username not in
(select name
from system.logstdby$skip_support
where action=0) ) and a.table_name not in (select DIRECTORY_NAME from dba_directories);
-- Grant Column privileges
select 'grant '||privilege||' ('||column_name||') '||
' on '||owner||'.'||table_name||' to '||grantee||' '||
decode(grantable,'YES','WITH Grant option')||';'
from dba_col_privs
where owner in
(select name
from system.logstdby$skip_support
where action=0)
and grantee in
(select username
from dba_users
where username not in
(select name
from system.logstdby$skip_support
where action=0) ) ;
--Grant directories privileges.
select 'grant '||privilege||' on directory "'||
owner||'"."'||table_name||'" to "'||grantee||'"'||
decode(grantable,'YES',' with grant option ')||
decode(hierarchy,'YES',' with hierarchy option ')||';'
from dba_tab_privs a
where owner in
(select name
from system.logstdby$skip_support
where action=0)
and grantee in
(select username
from dba_users
where username not in
(select name
from system.logstdby$skip_support
where action=0) ) and a.table_name in (select DIRECTORY_NAME from dba_directories);
select 'GRANT '||PRIVILEGE||' TO '||GRANTEE||';'
from dba_sys_privs where grantee in ('SRPT','WEBSW'); 注意修改对应的schema
spool off
set head on
数据库字符集的检查
select * from props$ where name like '%CHARACTERSET%';
3)源数据库备份
xtt.properties文件编辑
tablespaces=RCARD_DATA --要迁移的表空间
platformid=4
src_scratch_location=/oracle/datadump/xtts_dir/sdata
src_scratch_location=/oracle/datadump/xtts_dir/sdata
dest_scratch_location=/oracle/datadump/xtts_dir/sdata
dest_datafile_location=/oracle/datadump/xtts_dir/sdata
backupondest=/oracle/datadump/xtts_dir/xcdata
parallel=8
rollparallel=8
desttmpdir=/oracle/datadump/xtts_dir
getfileparallel = 8
xtts全备发起
export TMPDIR==/oracle/datadump/xtts_dir
$ORACLE_HOME/perl/bin/perl xttdriver.pl –backup
scp res.txt oracle/oracle/datadump/xtts_dir :
scp rmanconvert.cmd oracle/oracle/datadump/xtts_dir :
4)目标数据库还原文件
目标库恢复表空间
$ORACLE_HOME/perl/bin/perl xttdriver.pl --restore
5)数据库表空间增量备份恢复
xtts增量备份发起
$ORACLE_HOME/perl/bin/perl xttdriver.pl –backup
scp `cat incrbackups.txt` oracle@dest:/oracle/datadump/xtts_dir
scp res.txt oracle@dest:/oracle/datadump/xtts_dir
目标库增量同步
$ORACLE_HOME/perl/bin/perl xttdriver.pl --restore
此步骤需求定时反复执行不断同步源、目标两个表空间之间的数据
6)最终增量同步
源库表空间设置成readonly进行最后一次增量备份
alter tablespace TS1 read only;
$ORACLE_HOME/perl/bin/perl xttdriver.pl –backup
scp 'cat incrbackups.txt' oracle@dest:/dest_scratch_location
scp res.txt oracle@dest:/home/oracle/xtt
目标库恢复
$ORACLE_HOME/perl/bin/perl xttdriver.pl --restore
7)元数据导入
对象元数据导入目标数据库
create directory dpump_tts as '/home/oracle/destination/convert';
GRANT READ, WRITE ON DIRECTORY dpump_tts TO system;
$ORACLE_HOME/perl/bin/perl xttdriver.pl -e
create public database link ttslink connect to system identified by <password> using '<tns_to_source>';
impdp directory=DATA_PUMP_DIR logfile=tts_imp.log network_link=ttslink \
transport_full_check=no \
transport_tablespaces=TS1,TS2 \
transport_datafiles='+DATA/prod/datafile/ts1.285.771686721', \
'+DATA/prod/datafile/ts2.286.771686723', \
'+DATA/prod/datafile/ts2.287.771686743'
8)最终检查
表空间设置成读写状态
alter tablespace TS1 read write;
后续检查
--编译无效对象
@?/rdbms/admin/utlprp.sql 32
--对比无效对象
select r.owner, r.object_type, r.remote_cnt Source_Cnt, l.local_cnt Target_Cnt
from ( select owner, object_type, count(owner) remote_cnt
from dba_objects@XTTS_DBLINK
where owner not in
(select name
from system.logstdby$skip_support
where action=0) group by owner, object_type ) r
, ( select owner, object_type, count(owner) local_cnt
from dba_objects
where owner not in
(select name
from system.logstdby$skip_support
where action=0) group by owner, object_type ) l
where l.owner (+) = r.owner
and l.object_type (+) = r.object_type
and nvl(l.local_cnt,-1) != r.remote_cnt
order by 1, 3 desc;
--检查无效index
select owner, index_name, status from dba_indexes
where status='UNUSABLE' order by 1,2;
select i.owner, i.index_name, p.partition_name, p.status
from dba_ind_partitions p,dba_indexes i
where p.index_name=i.index_name and p.status='UNUSABLE'
order by 1,2,3;
select i.owner,i.index_name,s.subpartition_name,s.status from
dba_ind_subpartitions s,dba_indexes i where
s.index_name=i.index_name and s.status='UNUSABLE'
order by 1,2,3;
--检查新环境同义词,若无,则按以下脚本创建:
SELECT 'CREATE PUBLIC SYNONYM '||SYNONYM_NAME||' FOR '||TABLE_OWNER||'.'||TABLE_NAME||';'
FROM DBA_SYNONYMS WHERE TABLE_OWNER in ('**','test') AND OWNER = 'PUBLIC';
(create_synonym.txt)
----对象个数比较
注意:验证新旧环境对象个数前,原环境需要清理dba_recyclebin,保证检查对象一致。
purge recyclebin;
---验证新旧环境segment_type, TMP临时表空间和CLOB索引不一致则默认无异常:
【新环境执行】:
select r.owner, r.segment_type, r.remote_cnt Source_Cnt, l.local_cnt Target_Cnt
from ( select owner, segment_type, count(owner) remote_cnt
from dba_segments@ttslink
where owner not in
(select name
from system.logstdby$skip_support
where action=0)
AND SEGMENT_NAME NOT LIKE 'BIN%' group by owner, segment_type ) r
, ( select owner, segment_type, count(owner) local_cnt
from dba_segments
where owner not in
(select name
from system.logstdby$skip_support
where action=0) AND SEGMENT_NAME NOT LIKE 'BIN%' group by owner, segment_type ) l
where l.owner (+) = r.owner
and l.segment_type (+) = r.segment_type
and nvl(l.local_cnt,-1) != r.remote_cnt
order by 1, 3 desc
---验证新旧环境object_type
【新环境执行】:
select r.owner, r.object_type, r.remote_cnt Source_Cnt, l.local_cnt Target_Cnt
from ( select owner, object_type, count(owner) remote_cnt
from dba_objects@ttslink
where owner not in
(select name
from system.logstdby$skip_support
where action=0) group by owner, object_type ) r
, ( select owner, object_type, count(owner) local_cnt
from dba_objects
where owner not in
(select name
from system.logstdby$skip_support
where action=0) group by owner, object_type ) l
where l.owner (+) = r.owner
and l.object_type (+) = r.object_type
and nvl(l.local_cnt,-1) != r.remote_cnt
order by 1, 3 desc;
小结
实现跨版本的Oracle数据库迁移,根据应用系统数据库的实际情况分析我们往往会采取不同策略的迁移方案再应付。XTTS是其中一种可选的方案,从实际应用情况来看,它不需要额外的工具软件,同时接近于0停机的数据割接,对于数据量不大且交易不算太多的数据库而言也是一种良好的选择。
如果字段的最大可能长度超过255字节,那么长度值可能…
只能说作者太用心了,优秀
感谢详解
一般干个7-8年(即30岁左右),能做到年入40w-50w;有…
230721