目录
一、XTTS对平台和数据库的要求
1.1 操作系统层面
- 源端:任何平台都可,但不包括windows
- 目标端:仅支持64 bit的RedHat Linux或Oracle Linux
1.2 数据库层面
- 源端:Oracle Database - Enterprise Edition - Version 10.2.0.1 to 12.2
- 目标端:如果使用dbms_file_transfer(DFT),必须是11.2.0.4以上;
如果是RMAN,版本低于11.2.0.4时需要安装11.2.0.4的RDBMS运行11.2.0.4的实例
1.3 其他限制条件
- 源库的compatible参数不能大于目标端
- 源库和目标库字符集需要保持一致
- 目标端db_files参数必须大于源端
- 源库和生产必须处于归档模式
- 源库的RMAN配置中DEVICE TYPE DISK不能设置为COMPRESSED
- 要迁移的表空间数据文件必须都是online的或者不包括offline数据文件
- 排除系统表空间,避免冲突并检查业务表空间是否自包含
- 源库和目标库db block size必须一致
二、使用场景
- 大字节序平台到小字节序平台(AIX小机 - RedHat Linux)
- 可以实现不同版本数据库迁移+升级
- 迁移的数据量大且停机时间短
三、XTTS的前世今生
传统的传输表空间方式要求数据第一次由源端到目标端传输时,表空间必须置于read only模式,从而生产不可用。而XTTS方式则只需要在最后一次增量备份时将表空间置于read only模式,显著的减少了停机的时间
Oracle 8i 开始就引入的一种基于表空间传输TTS(Transporting Tablespaces)的物理迁移方法。支持相同平台、相同块(表空间的块,不是db_block)大小之间的表空间传输;
到了Oracle 9i后,TTS 开始支持同平台中,不同块大小的表空间传输,只能在相同平台之间进行数据移动
基于 TTS 的缺点,到了Oracle 10g正式 引入了跨平台的表空间传输方案—— XTTS(Cross Platform Transportable Tablespaces)。
XTTS相比TTS,有2个优点:一是可以实现跨平台和增量恢复,比如从小机到一体机。二是可以增量恢复,目的是为了减少停机时间。
比如同样迁移一套10T的数据库,TTS需要申请停机时间5小时,因为TTS一开始就要把表空间置为read only,但对比XTTS的区别在于最一开始的0级备份和前几次增量备份都不用把表空间改为read only,只是最后一次增量备份把表空间置为read only。这也就很大程度减少了停机时间。第一次备份的时候,可以选择开启块跟踪,第一次备份的时候会扫描整个数据文件,会把扫描的信息记录到跟踪文件里,后面的第二次、第三次的增量备份的时候,会利用跟踪文件判断更改的数据块来进行备份,这样也会提高后面备份的速度。
四、实现XTTS两个脚本的区别
使用XTTS进行数据库迁移时,可以使用Oracle提供的脚本(V3【Doc ID 1389592.1】,V4【Doc ID 2005729.1】)来完成。V3脚本可以实现非容器数据库迁移,V4脚本可以实现容器/非容器数据库迁移,并且迁移用到的命令相比V3更简单。
五、实现XTTS的两种方式
5.1 dbms_file_transfer(DFT)方式
通过DB_Link将数据文件从源系统传输到目标系统。不需要规划源系统和目标系统上的临时空间存放文件。在传输过程中自动进行数据文件转换 —— 没有单独的转换步骤。但该方式BUG较多,尤其是数据库版本较低(小于11.2.0.4)的情况下。
5.2 RMAN方式(推荐使用)
操作系统的字节序不同需要由RMAN转换。RMAN转换的输出将数据文件放置在其最终位置,目标数据库将在那里使用它们。
RMAN创建的数据文件副本在源系统和目标系统中都需要规划文件系统暂存这些文件。不过实际迁移过程中最好配置nfs使源端和目标端进行共享,这样整个迁移就会节省很多时间。
六、XTTS ——V3实验过程
6.1 实验环境
IP | 主机名 | 操作系统版本 | DB版本 | DB类型 | |
源端 | 192.168.6.100 | 11g | RedHat 7 x86 64bit | 11g | 单实例 |
目标端 | 192.168.6.101/102 | rac1/rac2 | RedHat 7 x86 64bit | 19c | rac |
6.2 解压并修改配置文件
6.2.1 源端解压脚本
[oracle@11g xtts]$ unzip rman_xttconvert_v3.zip
Archive: rman_xttconvert_v3.zip
inflating: xtt.properties
inflating: xttcnvrtbkupdest.sql
inflating: xttdbopen.sql
inflating: xttdriver.pl
inflating: xttprep.tmpl
extracting: xttstartupnomount.sql其中,常用的是下面2个文件
1)xttdriver.pl:调用xtts命令
2)xtt.properties:xtts的配置文件
6.2.2 源端编辑配置文件
[oracle@11g xtts]$ vi xtt.properties
以下为参数释义
tablespaces 要迁移的表空间名字,一定要用大写,且不要有空格和换行 platformid 源端操作系统平台号,可以数据库执行
select PLATFORM_ID,PLATFORM_NAME from v$database;
或
select * from v$transportable_platform ;进行确认srcdir DFT方式会用到,源库存放数据文件的路径,RMAN方式忽略即可 dstdir DFT方式会用到,目标库存放数据文件的路径,RMAN方式忽略即可 srclink DFT方式会用到,从目标端指向源端的 dblink,RMAN方式忽略即可 dfcopydir (源端)使用RMAN方式时指定的备份集存放位置 backupformat (源端)源端增量文件。安装了NFS的文件系统,它应该引用与目标系统的stageondest相同的NFS位置 stageondest (目标)定义dest端存放source端发送的副本和增量备份 storageondest (目标)使用RMAN方法时数据文件转换后的最终存放位置。 backupondest (目标)在“-r 前滚数据文件”步骤期间,增量备份格式转换后的输出目录 parallel 使用rman方式做prepare、convert时的并行度 rollparallel 前滚阶段的并行度
把解压和修改后的文件传到目标端:
[oracle@11g xtts]$ scp -r /u01/xtts/ 192.168.6.101:/u01/
rman_xttconvert_v3.zip 100% 34KB 19.4MB/s 00:00
xttcnvrtbkupdest.sql 100% 1390 1.9MB/s 00:00
xttdbopen.sql 100% 71 114.1KB/s 00:00
xttdriver.pl 100% 139KB 25.9MB/s 00:00
xttprep.tmpl 100% 11KB 12.7MB/s 00:00
xttstartupnomount.sql 100% 52 66.6KB/s 00:00
xtt.properties 100% 8014 9.2MB/s 00:00
6.2.3 两端设置变量
两端设置tmpdir ——— 设置为放脚本的位置,让中间输出的文件输出到这个目录
# export TMPDIR=/u01/xtts开启debug模式,在调用脚本时会输出详细信息
# export XTTDEBUG=1
6.3 源端备份和目标端恢复
第一次备份时,可以启动block change tracking功能后,level 0级的incremental backup依然要扫描整个数据文件,并将这些信息记录到跟踪文件中。change tracking file还没有映射到block的状态。对于后续级别的incremental backups,RMAN使用change tracking data决定哪些需要读取。通过消除对整个数据文件的read,提高了后续增量备份的速度。当最后一次增量备份结束后,关闭BCT功能。
启动BCT
SQL> ALTER DATABASE ENABLE BLOCK CHANGE TRACKING;关闭BCT
SQL> ALTER DATABASE DISABLE BLOCK CHANGE TRACKING;查看BCT状态
SQL> select status from v$block_change_tracking;
6.3.1 检查表空间自包含
自包含是表示用于传输的内部表空间集没有引用指向外部表空间集。
--检查表空间时,只检查业务表空间的自包含情况;系统表空间,临时表空间,undo表空间不在检查列
--在表空间传输的中,要求表空间集为自包含的,自包含表示用于传输的内部表空间集没有引用指向外部表空间集。常见的以下情况是违反自包含原则的:
1、索引在内部表空间集,而表在外部表空间集(相反地,如果表在内部表空间集,而索引在外部表空间集,则不违反自包含原则)。
2、分区表一部分区在内部表空间集,一部分在外部表空间集(对于分区表,要么全部包含在内部表空间集中,要么全不包含)。
3、如果在传输表空间时同时传输约束,则对于引用完整性约束,约束指向的表在外部表空间集,则违反自包含约束;如果不传输约束,则与约束指向无关。
4、表在内部表空间集,而lob列在外部表空间集,则违反自包含约束。符合自包含:表在tbs1,索引在users
create tablespace ts1 datafile size 20M;
alter tablespace ts1 add datafile size 20M;
create tablespace ts2 datafile size 20M;
alter tablespace ts2 add datafile size 20M;create user chen identified by chen default tablespace ts1;
grant dba to chen;
create table chen.t1 tablespace ts1 as select * from scott.dept;
create index chen.idx on chen.t1(deptno) tablespace users;exec dbms_tts.transport_set_check('TS1',TRUE);
select * from transport_set_violations;不符合自包含:
create index scott.idx2 on scott.dept(dname,loc) tablespace ts1;
exec dbms_tts.transport_set_check('TS1' ,TRUE);
select * from transport_set_violations; #此时这步会报错ORA-39907解决自包含报错:
alter index scott.idx2 rebuild tablespace users;
6.3.2 创建迁移需要的目录
源端:
[oracle@11g xtts]$ mkdir -p /u01/xtts/backupformat
[oracle@11g xtts]$ mkdir -p /u01/xtts/dfcopydir
目标端:
oracle@rac1:/u01/xtts> mkdir -p /u01/xtts/backupondest
oracle@rac1:/u01/xtts> mkdir -p /u01/xtts/stageondest
6.3.3 源端第一次全备
[oracle@11g xtts]$ perl xttdriver.pl -p
这步在源系统上执行以下操作:
创建表空间的数据文件副本,该表空间将在参数dfCopydir指定的位置传输。
验证表空间是online,处于读写模式,并且不包含offline数据文件。dfcopydir=/u01/xtts/dfcopydir参数定义的路径下会产生第一次备份的文件
/u01/xtts下会出现rmanconvert.cmd用于转换数据文件的脚本
/u01/xtts下会出现xttplan.txt文件,记录copy备份前数据文件的scn把备份文件复制到目标参数stageondest=/u01/xtts/stageondest对用的路径中
[oracle@11g xtts]$ scp /u01/xtts/dfcopydir/* 192.168.6.101:/u01/xtts/stageondest把转换脚本复制到目标端/u01/xtts/xtts/下
[oracle@11g xtts]$ scp /u01/xtts/rmanconvert.cmd 192.168.6.101:/u01/xtts
6.3.4 目标系统上转换数据文件副本
oracle@rac1:/u01/xtts>perl xttdriver.pl -c
转换数据文件步骤将路径位置中的数据文件副本转换为目标系统的Endian格式。转换的数据文件副本是在xtt.properties参数存储区指定的位置写入的。这是目标数据库使用数据文件时访问数据文件的最后位置。
6.3.5 源端第一次增量备份和目标端应用数据文件
1、源端进行增量备份
[oracle@11g xtts]$ perl xttdriver.pl -i
它创建本过程后面使用的下列文件:
这步生成两个文件:tsbkupmap.txt、incrbackups.txt,拷贝到目标端
### tsbkupmap.txt:增量文件的表空间名字、数据文件号和增量文件名字
### incrbackups.txt:增量文件的绝对路径
### xttplan.txt.new:新的记录scn的文件
[oracle@11g xtts]$ scp `cat incrbackups.txt` oracle@192.168.6.101:/u01/xtts/stageondest
[oracle@11g xtts]$ scp xttplan.txt tsbkupmap.txt oracle@192.168.6.101:/u01/xtts/2、目标端前滚数据文件
oracle@rac1:/u01/xtts> perl xttdriver.pl -r
注意:
- 每次执行这步时,必须复制xttplan.txt和tsbkupmap.txt文件。(scn)
- 目标端会重启
6.3.6 源端第二次增量备份和目标端应用数据文件
1、源端确定下一个增量备份的from_scn,将其记录在xttplan.txt文件中,然后创建下一个增量备份时使用该SCN。
[oracle@11g xtts]$ perl xttdriver.pl -s
这步会替换上次增量备份的xttplan.txt.new内容备份到xttplan.txt中,下次目标库前滚从这个scn开始2、第二次增量备份
[oracle@11g xtts]$ perl xttdriver.pl -i
生成两个文件:tsbkupmap.txt、incrbackups.txt,拷贝到目标端
$ scp `cat incrbackups.txt` oracle@192.168.6.101:/u01/xtts/stageondest
$ scp xttplan.txt tsbkupmap.txt oracle@192.168.6.101:/u01/xtts/3、目标端第二次前滚数据文件
oracle@rac1:/u01/xtts> perl xttdriver.pl -r
4、源端确定下一个增量备份的from_scn
[oracle@11g xtts]$ perl xttdriver.pl -s
6.4 备份过程中添加数据文件造成增量备份失败处理
按照报错提示操作即可:
1. 复制fixnewdf.txt到目标端
[oracle@11g xtts]$ scp /u01/xtts/fixnewdf.txt 192.168.6.101:/u01/xtts
2. 复制TS1_9.tf 到目标端/u01/xtts/dfcopydir
[oracle@11g xtts]$ scp /u01/xtts/dfcopydir/TS1_9.tf 192.168.6.101:/u01/xtts/stageondest3. 目标端执行下面的命令,将新添加的数据文件转换目标端字节序到对应storageondest参数定义的路径中(+DATADG)
oracle@rac1:/u01/xtts> perl xttdriver.pl --fixnewdf4. 源端重新增量备份:
[oracle@11g xtts]$ perl xttdriver.pl -i5. 目标端应用备份数据文件
oracle@rac1:/u01/xtts> perl xttdriver.pl -r
6.5 源端表空间只读
SQL> alter tablespace ts1 read only;
SQL> alter tablespace ts2 read only;
6.6 源端最后一次增量备份并恢复
[oracle@11g xtts]$ perl xttdriver.pl -i
[oracle@11g xtts]$ scp `cat incrbackups.txt` oracle@192.168.6.101:/u01/xtts/stageondest
[oracle@11g xtts]$ scp xttplan.txt tsbkupmap.txt oracle@192.168.6.101:/u01/xtts
6.7 目标端最后一次前滚数据文件
oracle@rac1:/u01/xtts> perl xttdriver.pl -r
6.8 目标端创建迁移用户
源端生成创建用户SQL
SQL> select 'create user "'||u.username||'" IDENTIFIED BY VALUES '''||p.password||''' default tablespace sysaux temporary tablespace TEMP '||(case u.account_status when 'LOCKED' then 'ACCOUNT LOCK;' when 'EXPIRED & LOCKED' then ' PASSWORD EXPIRE ACCOUNT LOCK;' else ' ;' end)
from dba_users u,sys.user$ p
where u.username in ('CHEN') and u.username=p.name order by u.username;目标端执行上步生成的SQL
SQL> create user "CHEN" IDENTIFIED BY VALUES '7A68FF917B75B6F6' default tablespace sysaux temporary tablespace TEMP;
6.9 元数据迁移
1、源端导出传输表空间元数据
#新建par参数文件
echo "
dumpfile=expdp_xttsdump_%U.dmp
directory=xtts
logfile=tts_expdp.log
transport_full_check=no
exclude=STATISTICS,INDEX_STATISTICS,TABLE_STATISTICS
transport_tablespaces=ts1,ts2
trace=480300
" > /u01/xtts/expdp_xtts.par
#执行
[oracle@11g xtts]$ expdp \'/ as sysdba\' parfile=/u01/xtts/expdp_xtts.par2、源端导出全库元数据
[oracle@11g xtts]$ expdp \"/ as sysdba\" directory=xtts logfile=xtts_full_metadata_`date +%Y%m%d%H%M`.log dumpfile=xtts_full_metadata_%u.dmp exclude=index,table,statistics content=metadata_only full=y parallel=8 cluster=N3、目标端生成数据文件列表
oracle@rac1:/u01/xtts> export XTTDEBUG=1
oracle@rac1:/u01/xtts> export TMPDIR=/rman/xtts/tmpdir
oracle@rac1:/u01/xtts> export PERL5LIB=$ORACLE_HOME/perl/lib
oracle@rac1:/u01/xtts> perl /rman/xtts/xttdriver.pl -e
oracle@rac1:/u01/xtts> cat /rman/xtts/tmpdir/xttplugin.txt4、目标端导入role
oracle@rac1:/u01/xtts> impdp \'/ as sysdba \' directory=xtts dumpfile=xtts_full_metadata_%u.dmp logfile=impdp_full_dblink_grant_role_job_`date +%Y%m%d%H%M`.log include=ROLE content=metadata_only cluster=N parallel=85、目标端导入表空间元数据
#新建par参数文件
echo "
dumpfile=expdp_xttsdump_%U.dmp
directory=xtts
logfile=impdp_tts_`date +%Y%m%d%H%M`.log
transport_datafiles=<3、目标端生成数据文件列表的xttplugin.txt>
" > /u01/xtts/impdp_xtts.par
oracle@rac1:/u01/xtts> impdp \"/ as sysdba\" parfile=/u01/xtts/impdp_xtts.par
6、目标端导入全库元数据
oracle@rac1:/u01/xtts> impdp \'/ as sysdba \' directory=xtts dumpfile=xtts_full_metadata_%u.dmp logfile=impdp_full_metadata_`date +%Y%m%d%H%M`.log content=metadata_only cluster=N parallel=87、目标端修改用户默认表空间
#源端查询用户默认表空间
SQL> set pages 200
SQL> select 'alter user '||username||' default tablespace '||default_tablespace||';'
from dba_users u where u.username in ('CHEN')
8、目标端编译失效对象
#查看失效对象个数:
SQL> select count(*) from dba_objects where status='INVALID';
#并行编译失效对象
SQL> execute sys.utl_recomp.recomp_parallel(32);9、临时表迁移
# 源端生成临时表DDL语句
SQL> SET LONG 1000000
SQL> SET PAGESIZE 3000
SQL> set LINES 200
SQL> SET HEADING OFF
SQL> SET VERIFY OFF
SQL> SET FEEDBACK OFF
SQL> SET ECHO ON
SQL> SET TIMING OFF
SQL> SET WRAP ON
SQL> SET LONGCHUNKSIZE 400
SQL> select dbms_metadata.get_ddl('TABLE',TABLE_NAME,OWNER) from DBA_TABLES where TEMPORARY='Y' and owner in ('CHEN');10、目标端修改用户默认profile
#检查profile是否导入成功
SQL> select * from dba_profiles;
#源端生成修改语句
SQL> set pages 2000
SQL> select 'alter user '||username||' profile '||PROFILE ||';' from dba_users;
11、目标端手动赋权
#源端生成角色授权脚本
SQL> SET SERVEROUTPUT ON
SQL> SET LINESIZE 1000
SQL> SET FEEDBACK OFF
SQL> SET TRIMSPOOL ON
SQL> SET long 999999
SQL> SET PAGESIZE 1000
SQL> spool grant_role_priv.sql
select 'grant '||GRANTED_ROLE||' to '||grantee||';'from dba_role_privs where admin_option='NO' and grantee in('CHEN')
union
select 'grant '||GRANTED_ROLE||' to '||grantee||' with admin option;' from dba_role_privs where admin_option='YES' and grantee in('CHEN');
spool off#源端生成系统权限授权脚本,目标端执行
SQL> spool grant_sys_priv.sql
select 'grant '||privilege||' to '||grantee||';' from dba_sys_privs where admin_option='NO' and grantee in('CHEN')
union
select 'grant '||privilege||' to '||grantee||' with admin option;' from dba_sys_privs where admin_option='YES' and grantee in('CHEN');
spool off#源端生成对象权限授权脚本
SQL> spool grant_tab_privs.sql
select 'grant ' || privilege || ' on ' || owner || '.'|| table_name || ' to ' || grantee || ';' from dba_tab_privs where grantable='NO' and grantee in('CHEN')
union
select 'grant ' || privilege || ' on ' || owner || '.'|| table_name || ' to ' || grantee || ' with grant option;' from dba_tab_privs where grantable='YES' and grantee in('CHEN');
spool off
目标端执行脚本
SQL> @grant_role_priv.sql
SQL> @grant_sys_priv.sql
SQL> @grant_tab_privs.sql
6.10 目标端验证
oracle@rac1:/u01/xtts> rman target /
RMAN> run{
allocate channel ch00 type disk;
allocate channel ch01 type disk;
allocate channel ch02 type disk;
allocate channel ch03 type disk;
allocate channel ch04 type disk;
allocate channel ch05 type disk;
allocate channel ch06 type disk;
validate database check logical;
}
6.11 目标端表空间置于read write状态
SQL> alter tablespace ts1 read write;
SQL> alter tablespace ts2 read write;
6.12 目标端收集统计信息
SQL> exec dbms_stats.gather_dictionary_stats;
SQL> exec dbms_stats.gather_fixed_objects_stats;
SQL> begin
dbms_stats.gather_database_stats(
ESTIMATE_PERCENT=>DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'for all columns size auto', cascade=>true, degree=>72);
end;
/