Oracle 8i引入了传输表空间特性(Transportable TableSpace,TTS),传输表空间是一种物理迁移数据库的方法,仅支持相同平台迁移,但在Oracle 10g中有所改进,可以支持跨平台迁移。由于在整个迁移过程中依然需要停机,而且停机时间长短与库的大小成正比,因此传输表空间并不是广大DBA的首选。
在小型机转X86的大趋势下,Oracle从11.2.0.4版本中开始支持跨平台增量传输表空间,XTTS(Cross Platform Transportable TableSpace)应运而生。TTS增强版的XTTS可以支持跨平台增量备份,使用增量备份的方式,可以在不中断业务的情况下进行前期的数据文件传输、数据文件转换等操作。然后通过多次增量备份恢复方式,使源端和目标端的数据差异降到最小,最终业务停机时间仅为最后一次增量备份和恢复所需的时间,整体停机时间稳定在1.5小时之内。下面就来具体演示如何使用XTTS完成跨平台迁移。
源端采用AIX小型机单机架构,数据库版本为Oracle 11.2.0.4。目标端采用Linux X86 RAC架构,数据库版本为Oracle 19.3。
表3-3列举了前置条件检查的各个条目。
表3-3 前置条件检查列表
如果目标最终的数据库版本为Oracle 11.2.0.3或更低版本,则需要在目标系统上运行Oracle 11.2.0.4实例,用于执行增量备份转换。表3-4列举了当前环境的资源配置情况。
表3-4 当前环境资源配置情况
生产库必须满足归档开启策略。
1.数据库版本检查
如果源端为Oracle 11.2.0.3的版本,那么为了避免Bug,需要安装p14192178_112030_Generic.zip补丁,解决Bug 14192178的问题,可参考文档Datapump Expdp and Impdp slow in 11.2.0.3 as a result of Queries on SYS.KU$_INDEX_VIEW KU$(文档ID:1459833.1)。
2.数据信息统计
以下是进行数据信息统计的步骤和内容。
1)检查数据库时区,命令如下:
SQL> select dbtimezone from dual; SQL> !date
2)检查数据库字符集,命令如下:
SQL> select * from nls_database_parameters where parameter like '%CHARACTERSET%';
3)检查目标端补丁,命令如下:
SQL> select 'opatch',comments from dba_registry_history;
4)检查目标端数据库组件的安装情况,命令如下:
SQL> select comp_name from dba_registry;
5)检查源端是否使用了索引压缩(key compression),命令如下:
SQL> select index_name,table_name from dba_indexes where compression='ENABLE'; SQL> select owner,table_name from dba_tables where iot_type is not null;
6)检查源端是否存在同名数据文件,命令如下:
SQL> select substr(file_name,-6,2) from dba_data_files where tablespace_name= 'TBS_NAME' order by 1;
7)检查源端compatible参数,命令如下:
SQL> show parameter compatible <!--必须大于10.2-->
8)统计源端表空间,命令如下:
SQL> select distinct(tablespace_name) from dba_data_files;
9)统计源端需要传输的数据文件大小,命令如下:
SQL> SELECT d.FILE_ID, d.TABLESPACE_NAME, (SELECT (SUM(nb.BYTES/1024/1024)) FROM dba_data_files nb WHERE nb.TABLESPACE_NAME = d.TABLESPACE_NAME) ts_size_m, d.FILE_NAME, (d.BYTES/1024/1024) file_size_m, (d.USER_BYTES/1024/1024) file_use_size_m FROM dba_data_files d WHERE d.TABLESPACE_NAME not in ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS2') ORDER BY file_id;
10)统计需要迁移的用户,命令如下:
SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'; SQL> SELECT d.username, d.default_tablespace, d.temporary_tablespace, d.account_status, d.created from dba_users d where d.account_status = 'OPEN' and d.username not like '%SYS%' order by d.CREATED desc; SQL> select ''''||username||''',' from dba_users where username not like '%SYS%' and account_status not like 'EXPIRED%';
11)用户权限收集,命令如下:
SQL> drop table t_tmp_user_lhr; SQL> create table t_tmp_user_lhr( id number, username varchar2(50), exec_sql varchar2(4000),create_type varchar2(20)); SQL> DROP sequence s_t_tmp_user_lhr; SQL> create sequence s_t_tmp_user_lhr; SQL> begin for cur in (SELECT d.username, d.default_tablespace, d.account_status, 'create user ' || d.username || ' identified by ' || d.username || ' default tablespace ' || d.default_tablespace || ' TEMPORARY TABLESPACE ' || D.temporary_tablespace || ';' CREATE_USER, replace(to_char(DBMS_METADATA.GET_DDL('USER', D.username)), chr(10), '') create_USER1 FROM dba_users d WHERE d.username in ('业务用户名')) loop INSERT INTO t_tmp_user_lhr (id, username, exec_sql, create_type) values (s_t_tmp_user_lhr.nextval, cur.username, cur.CREATE_USER, 'USER'); INSERT INTO t_tmp_user_lhr (id, username, exec_sql, create_type) SELECT s_t_tmp_user_lhr.nextval, cur.username, CASE WHEN D.ADMIN_OPTION = 'YES' THEN 'GRANT ' || d.privilege || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION ;' ELSE 'GRANT ' || d.privilege || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_SYS_PRIVS' FROM dba_sys_privs d WHERE D.GRANTEE = CUR.USERNAME; INSERT INTO t_tmp_user_lhr (id, username, exec_sql, create_type) SELECT s_t_tmp_user_lhr.nextval, cur.username, CASE WHEN D.ADMIN_OPTION = 'YES' THEN 'GRANT ' || d.GRANTED_ROLE || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION;' ELSE 'GRANT ' || d.GRANTED_ROLE || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_ROLE_PRIVS' FROM DBA_ROLE_PRIVS d WHERE D.GRANTEE = CUR.USERNAME; INSERT INTO t_tmp_user_lhr (id, username, exec_sql, create_type) SELECT s_t_tmp_user_lhr.nextval, cur.username, CASE WHEN d.grantable = 'YES' THEN 'GRANT ' || d.privilege || ' ON ' || d.owner || '.' || d.table_name || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION ;' ELSE 'GRANT ' || d.privilege || ' ON ' || d.owner || '.' || d.table_name || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_TAB_PRIVS' FROM DBA_TAB_PRIVS d WHERE D.GRANTEE = CUR.USERNAME; end loop; COMMIT; end; / SQL> SELECT * FROM t_tmp_user_lhr; SQL> SELECT id,username,CREATE_TYPE,EXEC_SQL FROM t_tmp_user_lhr where CREATE_TYPE not in ('USER');
12)统计用户表格的规模,命令如下:
SQL> select d.owner, (sum(bytes) / 1024 / 1024) sizes_m from dba_segments d where d.owner in ('业务用户名') AND NOT EXISTS (SELECT 1 FROM DBA_RECYCLEBIN B WHERE B.object_name= D.segment_name AND D.OWNER=B.owner) GROUP BY d.owner order by sum(bytes) desc;
13)统计用户对象的个数和类型,命令如下:
SQL> SELECT D.OWNER,COUNT(1) FROM dba_objects d WHERE d.OWNER in ('业务用户') and d.OWNER not in ('PUBLIC') AND NOT EXISTS (SELECT 1 FROM DBA_RECYCLEBIN B WHERE B.object_name= D.OBJECT_NAME AND D.OWNER=B.owner) GROUP BY D.OWNER ORDER BY COUNT(1) desc; SQL> SELECT D.OWNER, D.OBJECT_TYPE, COUNT(1) FROM dba_objects d WHERE d.OWNER in ('业务用户') and d.OWNER not in ('PUBLIC') AND NOT EXISTS (SELECT 1 FROM DBA_RECYCLEBIN B WHERE B.object_name = D.OBJECT_NAME AND D.OWNER = B.owner) GROUP BY D.OWNER, D.OBJECT_TYPE ORDER BY D.OWNER ,COUNT(1) desc;
14)备份对象信息,以方便与无效对象进行比对。
记录所有业务用户下的对象信息,命令如下:
SQL> spool invald.lst SQL> select owner,object_name,object_type,status from dba_objects where status<> 'VALID' and owner in ('业务用户'); SQL> select count(*),status from dba_objects where owner in ('业务用户') group by status; SQL> spool off
创建对比表格,命令如下:
SQL> create table invalid_object_201911 as select * from dba_objects where status<>'VALID';
查看业务用户的对象状态个数,命令如下:
SQL> select count(*),status from dba_objects where owner in ('业务用户') group by status;
15)检查无效index,命令如下:
SQL> select owner, index_name, status from dba_indexes where status= 'UNUSABLE' order by 1,2; SQL> 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; SQL> 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;
16)确定SYS及SYSTEM下是否存在业务对象。检查SYS和SYSTEM的重复对象,命令如下:
SQL> select object_name, object_type from dba_objects where (object_name,object_type) in (select object_name,object_type from dba_objects where owner = 'SYS') and owner = 'SYSTEM'; OBJECT_NAME OBJECT_TYPE -------------------------------------------- ------------------- AQ$_SCHEDULES TABLE DBMS_REPCAT_AUTH PACKAGE AQ$_SCHEDULES_PRIMARY INDEX DBMS_REPCAT_AUTH PACKAGE BODY <!--若返回相同的内容,则表示正常-->
检查SYSTEM表空间下是否存在业务对象,命令如下:
SQL> select owner,segment_name,segment_type,tablespace_name from dba_segments where tablespace_name in ('SYSTEM','SYSAUX') and owner in ('业务用户');
17)确定平台字节序,命令如下:
SQL> select tp.platform_name, tp.endian_format from v$transportable_platform tp where tp.platform_name in ('Linux x86 64-bit', 'AIX-Based Systems (64-bit)'); PLATFORM_NAME ENDIAN_FORMAT ---------------------------------------- -------------- AIX-Based Systems (64-bit) Big Linux x86 64-bit Little
18)判断表空间是否具有自包含特性,命令如下:
SQL> execute sys.dbms_tts.transport_set_check('所有需要迁移的业务表空间',true); SQL> select * from sys.transport_set_violations;
19)获取需要传输的表空间,命令如下:
SQL> set serveroutput on SQL> declare tsname varchar(30); i number := 0; begin dbms_output.put('tablespaces='); for ts in (select tablespace_name from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX') and contents = 'PERMANENT' order by tablespace_name) loop if (i!=0) then dbms_output.put_line(tsname||','); end if; i := 1; tsname := ts.tablespace_name; end loop; dbms_output.put_line(tsname); dbms_output.put_line(''); end; /
20)检查兼容的高级队列(Compatible Advanced Queues),命令如下:
SQL> select owner,queue_table,recipients,compatible from dba_queue_tables where recipients= 'MULTIPLE' and compatible like '%8.0%' ;
21)检查基于XMLSchema的XMLType对象,命令如下:
SQL> SELECT distinct OWNER FROM DBA_XML_SCHEMAS; SQL> 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;
22)检查SPATIAL空间组件对象,命令如下:
SQL> select owner,index_name from dba_indexes where ityp_name = 'SPATIAL_INDEX' ; SQL> select owner, table_name, column_name from dba_tab_columns where data_type = 'SDO_GEOMETRY' and owner != 'MDSYS' order by 1,2,3;
23)检查外部表,命令如下:
SQL> select distinct owner from DBA_EXTERNAL_TABLES;
24)检查索引组织表(Index Organized Table,IOT),命令如下:
SQL> select distinct owner from dba_tables where IOT_TYPE is not null ;
25)检查临时表,命令如下:
SQL> SELECT owner,table_name FROM DBA_TABLES WHERE TEMPORARY = 'Y' AND OWNER IN ('业务用户');
26)检查物化视图,命令如下:
SQL> select owner, count (*) from dba_mviews group by owner;
27)检查永久表空间,命令如下:
SQL> select t.TABLESPACE_NAME TABLESPACE_NAME, count (f.FILE_ID), sum (f.bytes/1024/1024/1024) GB FROM dba_tablespaces t, dba_data_files f where t.TABLESPACE_NAME=f.TABLESPACE_NAME and t.tablespace_name not in (根据需求排除) and t.contents = 'PERMANENT' group by t.TABLESPACE_NAME order by 2;
28)检查回收站,命令如下:
SQL> select count (*) from dba_recyclebin;
29)检查是否存在用户使用TSTZ字段,命令如下:
SQL> select c.owner || '.' || c.table_name || '(' || c.column_name || ') -' || c.data_type || ' ' col from dba_tab_cols c, dba_objects o where c.data_type like '%WITH TIME ZONE' and c.owner=o.owner and c.table_name = o.object_name and o.object_type = 'TABLE' order by col;
30)检查表空间是否加密,命令如下:
SQL> select tablespace_name,ENCRYPTED from dba_tablespaces;
31)检查是否存在加密字段,命令如下:
SQL> select * from DBA_ENCRYPTED_COLUMNS;
32)检查Opaque Types类型字段,命令如下:
SQL> select distinct owner ,DATA_TYPE from dba_tab_columns where owner in ('业务用户');
33)检查表空间和数据文件的状态,命令如下:
SQL> select tablespace_name,status from dba_tablespaces; SQL> select STATUS,ONLINE_STATUS, count (*) from dba_data_files group by STATUS,ONLINE_STATUS;
34)比对新旧环境中的profile是否一致,命令如下:
SQL> select distinct (t.pro) from ( select s.profile pro, l.profile pro2 from dba_profiles@ttslink s, dba_profiles l where s.profile = l.profile(+)) t where t.pro2 is null order by t.pro;
3.创建directory
在源端创建目录(directory),用于指向源端数据文件所在的位置,命令如下:
SQL> create directory sourcedir as '/dev'; SQL> grant all on directory sourcedir to public;
由于本案例中的数据文件是裸设备,所以代码中写的是/dev。
4.使用NFS配置共享文件夹
1)目标端配置。不同版本的系统开启NFS(Network File System,网络文件系统)的方法不同。
Linux 6中开启NFS的方法如下:
shell> service nfs start shell> chkconfig nfs on
Linux 7中开启NFS的方法如下:
shell> systemctl start nfs.service shell> systemctl enable nfs.service shell> vi /etc/exports /backup 130.36.21.89(rw,sync,all_squash) shell> exportfs –a
2)源端配置的命令如下:
shell> mount -o cio,rw,bg,hard,nointr,rsize=32768,wsize=32768,proto=tcp,noac,vers=3, timeo=600 132.151.59.16:/backup/bak /backup/bak
至此,源端和目标端均有/backup/bak目录了。
在源端挂载目标端网络文件系统时,在目标端/etc/exports中需要指定源端物理IP,否则会造成源端挂载失败,强烈建议挂载到二级目录,比如/backup/bak这种形式,否则可能会因为网络文件系统服务中断,而造成AIX生产端数据库服务异常。
5.准备XTTS介质
将介质“rman-xttconvert_3.0.zip”上传到生产源端的/backup/bak目录下。
6.编辑xtt.properties文件
编辑xtt.properties,添加如表3-5所示的参数内容。
表3-5 xtt.properties参数说明
对于表3-5中的第一条tablespaces参数,命令参考脚本如下:
SQL> set serveroutput on SQL> declare tsname varchar(30); i number := 0; begin dbms_output.put('tablespaces='); for ts in (select tablespace_name from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX') and contents = 'PERMANENT' order by tablespace_name) loop if (i!=0) then dbms_output.put_line(tsname||','); end if; i := 1; tsname := ts.tablespace_name; end loop; dbms_output.put_line(tsname); dbms_output.put_line(''); end; /
7.获取目标端所需创建的表空间语句
创建所有表空间语句,以用于从生产端导入所有权限及用户,相关脚本如下:
SQL> set heading off feedback off trimspool on linesize 500 SQL> spool tts_create_ts.sql SQL> prompt /* ===================== */ SQL> prompt /* Create user tablespaces */ SQL> prompt /* ===================== */ SQL> select 'create TABLESPACE ' || tablespace_name || ' DATAFILE ' ||'''+DATA/orajf/'||tablespace_name||'.dbf'''||' size 10M autoextend on;' from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX',’USERS’) and contents = 'PERMANENT'; SQL> prompt /* ===================== */ SQL> prompt /* Create user temporary tablespaces */ SQL> prompt /* ===================== */ SQL> select 'create TEMPORARY TABLESPACE ' || tablespace_name || ' TEMPFILE ' ||'''+DATA/orajf/'||tablespace_name||'.dbf'''||' size 10M autoextend on;' from dba_tablespaces where tablespace_name not in ('TEMP’) and contents = ''TEMPORARY''; SQL> spool off
1.安装集群创建数据库
安装Oracle 19.3集群及数据库软件。创建数据库时,原则上,数据库的名称应与生产保持一致,需要特别注意的是,字符集必须与生产保持一致,目标端同样必须满足归档开启策略。
源端和目标端数据库service_names参数设置需要保持一致,否则会造成应用连接失败的问题。
2.创建目标目录
创建目标端数据文件destdir最终所在的目录,命令如下:
SQL> create directory destdir as '+DATA/orajf/'; SQL> grant all on directory destdir to public;
3.创建DATA_PUMP_DIR
创建DATA_PUMP_DIR目录,用于导入元数据,命令如下:
SQL> create or replace directory DATA_PUMP_DIR as '/backup/bak'; SQL> grant all on directory DATA_PUMP_DIR to public;
4.创建DB_LINK
创建连接串,命令如下:
shell> vi /u01/app/oracle/product/19.3/db/network/admin/tnsnames.ora XTTS = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 130.36.23.19)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orajf) ) )
创建连接源端数据库的DBLINK,命令如下:
SQL> create public database link ttslink connect to system identified by zj130lt using 'xtts';
5.创建所需的表空间
根据3.4.2节介绍的获取创建表空间文件的语句在目标端创建所需的表空间。
6.目标端导入生产库用户及权限
目标端导入生产库用户及权限的语句如下:
shell> impdp \'/ as sysdba\' DIRECTORY=DATA_PUMP_DIR LOGFILE=dp_userimp01.log NETWORK_LINK=TTSLINK FULL=y INCLUDE=USER,ROLE,ROLE_GRANT,PROFILE,function
导入完成后,需要删除相应的表空间。需要明确的是,该操作是在目标端进行的,操作前请谨记,一定要再三确认。
SQL> set heading off feedback off trimspool on linesize 500 SQL> spool tts_drop_ts.sql SQL> prompt /* ===================== */ SQL> prompt /* Drop user tablespaces */ SQL> prompt /* ===================== */ SQL> select 'DROP TABLESPACE ' || tablespace_name || ' INCLUDING CONTENTS AND DATAFILES;' from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX',’USERS’) and contents = 'PERMANENT'; SQL> prompt /* ===================== */ SQL> prompt /* Drop user temporary tablespaces */ SQL> prompt /* ===================== */ SQL> select 'DROP TABLESPACE ' || tablespace_name || ' INCLUDING CONTENTS AND DATAFILES;' from dba_tablespaces where tablespace_name not in ('TEMP’) and contents = ''TEMPORARY''; SQL> spool off
7.删除目标端的USERS表空间
为了保证源端的USERS表空间能够顺利传输过来,需要先删除目标端的USERS表空间,删除命令如下:
SQL> alter database default tablespace SYSAUX; SQL> drop tablespace users including contents and datafiles;
8.设置TMPDIR
设置TMPDIR的语句如下:
源端(生产端):shell> export TMPDIR=/opt/oracle/tmp 目标端(新库):shell> export TMPDIR=/home/oracle/tmp
1.数据全量传输阶段
数据全量传输可采用如下两种方式。
·Phase 2A-dbms_file_transfer Method。
·Phase 2B-RMAN Backup Method。
增量阶段应打开块跟踪,以加快速度,命令如下:
SQL> alter database enable block change tracking using file '/rman/trace.log'; SQL> select status from v$block_change_tracking;
1)生成增量所需的文件,命令如下:
shell> export TMPDIR=/opt/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -S xttplan.txt <!--记录数据文件SCN号--> xttnewdatafiles.txt <!--记录数据文件位置-->
新生成文件需要提前备份!
2)以手动RMAN复制的方式传输文件。源端查询以下语句,复制源端数据文件至NFS共享目录/backup/bak中:
select 'copy datafile '||''''||file_name||''''||' to '||''''||'/backup/bak/'||substr (file_name,instr(file_name,'/',-1)+1)||'.dbf'''||';' from dba_data_files where TABLESPACE_NAME not in ('SYSTEM','SYSAUX','UNDOTBS1');
3)目标端手动修改数据文件。修改数据文件权限,命令如下:
shell> chown grid.oinstall *.dbf
查询语句在源端执行查询操作,在目标端执行convert操作,命令如下:
SQL> select 'CONVERT FROM PLATFORM '||''''||'AIX-Based Systems (64-bit)'||''''||' PARALLELISM 10'||' datafile '||''''||'/backup/bak/'||SUBSTR(NAME,INSTR(NAME, '/',-1)+1)|| '.dbf'||''''||' format '||''''||'+DATA/orajf/'||SUBSTR(NAME,INSTR (NAME,'/',-1)+1)||'.dbf'''||';' from v$datafile;
2.增量恢复
1)源端执行。检查增量备份的路径,比如,xtt.properties文件的路径信息、权限等。
源端执行增量备份:
shell> export TMPDIR=/opt/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -i (nohup后台执行)
将以下源端文件复制或替换至目标端。
xttnewdatafiles.txt xttplan.txt tsbkupmap.txt shell> scp xttplan.txt 132.151.59.16:/home/oracle/tmp/ shell> scp tsbkupmap.txt 132.151.59.16:/home/oracle/tmp/
2)目标端前滚。修改增量备份片权限,命令如下:
shell> chown grid.oinstall *_1_1 shell> chmod 775 *_1_1
目标端增量应用日志,命令如下:
shell> export TMPDIR=/home/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -r
可通过查看数据文件的时间来确定增量是否成功。
3)在源端确认下一个增量的SCN,命令如下:
shell> export TMPDIR=/opt/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -s
继续轮询增量恢复。
1.最后一次增量
1)将源端表空间设置为READ ONLY(只读)。在生产端运行如下命令,以获取READ ONLY脚本:
SQL> set heading off feedback off trimspool on linesize 500 SQL> spool tts_tsro.sql SQL> prompt /* =================================== */ SQL> prompt /* Make all user tablespaces READ ONLY */ SQL> prompt /* =================================== */ SQL> select 'ALTER TABLESPACE ' || tablespace_name || ' READ ONLY;' from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX','UNDOTBS1') and contents = 'PERMANENT'; SQL> spool off
在源端执行以上获取到的命令。
检查表空间状态是否为只读(read only),命令如下:
SQL> select tablespace_name,status,contents from dba_tablespaces;
2)停止业务进行最后一次增量备份。在源端执行以下语句:
shell> export TMPDIR=/opt/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -i
最后一次增量结束之后关闭块跟踪,命令如下:
SQL> alter database disable block change tracking;
将以下源端文件复制或替换到目标端。
源端目录:/opt/oracle/tmp
目标端目录:/home/oracle/tmp/
命令如下:
xttnewdatafiles.txt xttplan.txt tsbkupmap.txt shell> scp xttplan.txt 132.151.59.16:/home/oracle/tmp/ shell> tsbkupmap.txt 132.151.59.16:/home/oracle/tmp/
3)目标端最后一次前滚。修改增量备份片权限,命令如下:
shell> chown grid.oinstall *_1_1 shell> chmod 775 *_1_1
目标端增量应用日志,命令如下:
shell> export TMPDIR=/home/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -r
2.元数据同步
1)确认生产是否新增数据文件,命令如下:
SQL> select name,CREATION_TIME from v$datafile order by CREATION_TIME asc;
2)元数据同步。目标端利用脚本生成元数据同步的导入语句(xttplugin.txt),命令如下:
shell> export TMPDIR=/home/oracle/tmp shell> export XTTDEBUG=1 shell> $ORACLE_HOME/perl/bin/perl xttdriver.pl -e
备份生成的xttplugin.txt文件,并自定义修改,以下是笔者的修改项:
directory=DATA_PUMP_DIR exclude=STATISTICS logfile=tts_imp_20191113.log network_link=ttslink
transport_tablespaces和transport_datafiles信息可以通过以下脚本获取。
获取transport_tablespaces的命令如下:
SQL> set serveroutput on SQL> declare tsname varchar(30); i number := 0; begin dbms_output.put('transport_tablespaces='); for ts in (select tablespace_name from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX') and contents = 'PERMANENT' order by tablespace_name) loop if (i!=0) then dbms_output.put_line(tsname||', \'); end if; i := 1; tsname := ts.tablespace_name; end loop; dbms_output.put_line(tsname); dbms_output.put_line(''); end; /
获取transport_datafiles的命令如下:
SQL> set serveroutput on SQL> declare fname varchar(513); i number := 0; begin dbms_output.put('transport_datafiles='); for df in (select file_name from dba_tablespaces a, dba_data_files b where a.tablespace_name = b.tablespace_name and a.tablespace_name not in ('SYSTEM','SYSAUX') and contents = 'PERMANENT' order by a.tablespace_name) loop if (i!=0) then dbms_output.put_line('''+DATA/zwhis/'||substr(fname,instr(fname, '/',-1)+1)||''', '); end if; i := 1; fname := df.file_name; end loop; dbms_output.put_line('''+DATA/zwhis/'||substr(fname,instr(fname, '/',-1)+1)||''''); dbms_output.put_line(''); end; /
在目标端执行修改之后的脚本,结束后检查目标端的表空间和数据文件状态,命令如下:
SQL> select tablespace_name,file_name,status from dba_data_files; SQL> select name,status from v$datafile;
3)验证传输的数据。使用RMAN验证传输过来的表空间是否存在物理或逻辑坏块,格式如下:
RMAN> validate tablespace 列出传输的表空间 check logical;
4)将目标端表空间设置成READ WRITE(读写)模式。在目标端运行如下命令以获取READ WRITE脚本:
SQL> set heading off feedback off trimspool on linesize 500 SQL> spool tts_tsro.sql SQL> prompt /* ==================================== */ SQL> prompt /* Make all user tablespaces READ WRITE */ SQL> prompt /* ==================================== */ SQL> select 'ALTER TABLESPACE ' || tablespace_name || ' READ WRITE;' from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX','UNDOTBS1') and contents = 'PERMANENT'; SQL> spool off
最后检查表空间状态,执行如下命令:
SQL> select tablespace_name,status,contents from dba_tablespaces;
5)同步临时表。使用数据泵impdp的方式同步元数据时,临时表数据是不会自动同步的,需要在目标库中手动创建临时表。
在生产端查询临时表格,查询语句如下:
SQL> select TEMPORARY,table_name,owner from dba_tables where owner in ('业务用户名');
获取生产端的建表语句,命令如下:
SQL> spool get_tmptable_ddl.sql SQL> select dbms_metadata.get_ddl('TABLE','临时表格名','用户名') FROM dual;
以上语句可以直接合并为如下代码段:
SQL> select 'select dbms_metadata.get_ddl(' || '''' || 'TABLE' || '''' || ',' || '''' || table_name || '''' || ',' || '''' || owner || '''' || ') FROM dual;' from dba_tables where owner in ('业务用户名') and TEMPORARY = 'Y';
6)导入源库的权限。
方法一,使用脚本导入:
SQL> spool grants.sql SQL> SELECT EXEC_SQL FROM t_tmp_user_lhr where CREATE_TYPE not in ('USER'); SQL> spool off
方法二,使用impdp导入:
shell> impdp \'/ as sysdba\' DIRECTORY=DATA_PUMP_DIR LOGFILE=dp_userimp01.log NETWORK_LINK=ttslink FULL=y INCLUDE=GRANT
7)导入DB_LINK对象,命令如下:
shell> impdp \'/ as sysdba\' DIRECTORY=DATA_PUMP_DIR LOGFILE=dp_userimp03.log NETWORK_LINK=ttslink FULL=y INCLUDE=DB_LINK
在SYS用户下,对DB_LINK缺失问题的处理方法如下:
SQL> select dbms_metadata.get_ddl('DB_LINK','DBLINK_NAME','SYS') from dual;
8)导入其他对象,命令如下:
shell> impdp \'/ as sysdba\' DIRECTORY=DATA_PUMP_DIR LOGFILE=dp_userimp02.log NETWORK_LINK=ttslink FULL=y INCLUDE=INDEX,FUNCTION,VIEW,SYNONYM,PACKAGE_BODY,SEQUENCE,PACKAGE,JOB, TRIGGER,PROCEDURE,TPYE
9)编译无效对象,命令如下:
SQL> @?/rdbms/admin/utlrp.sql
10)修改默认表空间,命令如下:
SQL> alter database default tablespace USERS;
11)导入目标端的统计信息,命令如下:
shell> impdp \'/ as sysdba\' DIRECTORY=DATA_PUMP_DIR LOGFILE=dp_userimp02.log NETWORK_LINK=ttslink FULL=y INCLUDE= STATISTICS
3.数据比对
1)对象数量的比对,命令如下:
SQL> SELECT D.OWNER,COUNT(1) FROM dba_objects d WHERE d.OWNER in ('业务用户名') and d.OWNER not in ('PUBLIC') AND NOT EXISTS (SELECT 1 FROM DBA_RECYCLEBIN B WHERE B.object_name= D.OBJECT_NAME AND D.OWNER=B.owner) GROUP BY D.OWNER ORDER BY owner desc;
2)对象类型的比对,命令如下:
SQL> SELECT D.OWNER, D.OBJECT_TYPE, COUNT(1) FROM dba_objects d WHERE d.OWNER in ('业务用户名') and d.OWNER not in ('PUBLIC') AND NOT EXISTS (SELECT 1 FROM DBA_RECYCLEBIN B WHERE B.object_name = D.OBJECT_NAME AND D.OWNER = B.owner) GROUP BY D.OWNER, D.OBJECT_TYPE ORDER BY D.OWNER ,COUNT(1) desc;
3)账号权限和同义词验证,命令如下:
SQL> select SYNONYM_NAME from dba_synonyms where owner in ('业务用户名');
4)检查数据文件头状态,命令如下:
SQL> select STATUS,ERROR,TABLESPACE_NAME from V$DATAFILE_HEADER;
5)表空间校验。确认owner用户的DEFAULT_TABLESPACE、TEMPORARY_TABLESPACE,以及所有用户在相关表空间上的配额情况,将之前创建的owner用户的默认表空间修改为正确的默认表空间。
表3-6列举了验证结果比对项清单。
表3-6 比对项清单
迁移失败回退操作只需要将源生产数据库表空间置换为read write、源端JOB进程调整为原值,并启动源端监听即可,操作在5分钟之内即可完成。
为了避免在迁移过程中触发大量JOB,建议在迁移过程中禁用生产端和目标端JOB。禁用JOB的命令如下:
SQL> alter system set job_queue_processes=0 scope=both sid='*';
迁移和应用测试结束,且三方确认无误后,即可开启JOB。启用JOB的命令如下:
SQL> alter system set job_queue_processes=原值 scope=both sid='*';