本文轉自 https://blog.csdn.net/Enmotech/article/details/80045576
作者 | 羅貴林: 雲和恩墨技術工程師,具有8年以上的 Oracle 數據庫工作經驗,曾任職於大型的國家電信、省級財政、省級公安的維護,性能調優等。精通 Oracle 數據庫管理,調優,問題診斷。擅長 SQL 調優,Oracle Rac 等維護,管理。
1 跨平台跨版本遷移方案對比
針對跨平台跨版本的遷移,主要有以下三種方式:數據泵、GoldenGate / DSG、XTTS,針對停機時間、復雜度、實施准備時間,做了以下列表比對:
客戶的需求都是最短停機時間,最少數據丟失。對於 GoldenGate / DSG 來說它的停機時間是最短的,但實施准備時間最長,復雜度最高;數據泵是停機時間最長,實施准備時間最短;XTTS 是介於這兩者之間的,同時滿足客戶提出的短停機時間、低實施成本需求。
數據泵比較適用的場景就是數據量比較小、數據大概在 5T 以下,使用數據泵會方便很多。
GoldenGate / DSG 比較適用大數據量的數據分發,災備庫建設。
XTTS 是單次數據庫跨平台、跨版本遷移利器,相同平台,相同版本遷移首選 rman。
在 Oracle11g 中的 RMAN 支持不同操作系統和不同 DB 版本之間的使用,關於 RMAN 的兼容性。如下圖示:
注意以下操作系統的組合,這里假設 DB version 相同:
(1)For Oracle Database 10g Release 2 and above releases: --在 Oracle 10gR2 之后的版本,支持如下操作系統之間的 RMAN 操作: Solaris x86-64 <-> Linux x86-64 HP-PA <-> HP-IA Windows IA (64-bit) / Windows (64-bitItanium) <-> Windows 64-bit for AMD / Windows (x86-64) (2)For Oracle Database 11g Release 1 and above releases (requires minimum 11.1 compatible setting): --在 Oracle 11gR1 之后的版本,支持如下操作系統之間的 RMAN 操作,當然這里也包含第一條里提到的 10gR2 后的組合。 Linux <-> Windows (3)For Oracle Database 11g Release 2(11.2.0.2) and above releases: Solaris SPARC (64-bit) <-> AIX(64-bit) - Note: this platform combination is currently not supported due to Bug 12702521 --在 11gR2 中,因為 Bug 12702521 的存在,Solaris SPARC (64-bit) <-> AIX (64-bit) 這2個版本之間不能進行 RMAN 操作。
XTTS 同樣須遵循 Oracle 升級路線:
Oracle 9i/10g/11g 數據庫升級路線圖(upgrade roadmap)
2 XTTS 各版本功能對比
XTTS (Cross Platform Transportable Tablespaces) 跨平台遷移表空間,是 Oracle 自10g 推出的一個用來移動單個表空間數據以及創建一個完整的數據庫從一個平台移動到另一個平台的遷移備份方法。它是 Oracle 8i 開始就引入的一種基於表空間傳輸的物理遷移方法,命名為 TTS,不過 8i 的表空間遷移僅支持相同平台、相同塊大小之間的表空間傳輸,從 Oracle 9i 開始,TTS 開始支持同平台中,不同塊大小的表空間傳輸,這個時候很多數據庫管理員就注意到了 TTS 在實際工作中的應用,不過由於每次移動表空間都需要停機、停業務,而 9i 的 TTS 只能在相同平台之間進行數據移動,相比 Oracle RMAN 本身的快捷方便,更多人更願意選擇使用 RMAN 進行數據備份、數據移動,基於 TTS 的這些缺點,Oracle 10g 時代引入了跨平台的表空間傳輸方案 XTTS,標志着第一代 XTTS 的誕生。
可以理解為 TTS 就是傳輸表空間,把表空間傳輸出去,數據從一個庫傳輸到另外一個庫,不支持增量備份,而 XTTS 是在 TTS 基礎上做了一些更新,支持了跨平台,支持增量備份。
XTTS 各版本的功能比對如下,表一:XTTS 各版本功能比對表
在 Oracle11gR2(推薦使用 11.2.0.4 及之后版本)以后,Oracle 推出了通過前滾數據文件,拷貝數據后再進行多次增量備份的 XTTS 來完成遷移過程,在這個過程中通過開啟塊跟蹤特性,根據 SCN 號來執行一系列的增量備份,並且通過對塊跟蹤文件的掃描,來完成增量數據的增量備份應用,最后在通過一定的停機時間,在源庫 read only 的狀態下進行最后一次增量備份轉換應用,使得整個遷移過程的停機時間同源庫數據塊的變化率成正比。這樣大大的縮短了停機時間。
3 XTTS 前置條件檢查
使用 XTTS 進行數據遷移需要具備的哪些前置條件?
可列出如下表格進行詳細對比:
說明:
- 如果源端空間不夠可以采用 NFS 磁盤掛載的方式,即將 Linux 的 NFS 文件系統掛載到中間環境(AIX 小機)的方式。
- XTTS 基於 RMAN 備份的方法,對於空間需求要求較高。
- 目標端新環境,提前安裝並部署好 Oracle+ASM 環境,同時創建與現有生產庫字符集一致的數據庫。
4 XTTS 三種遷移方式
采用 XTTS 遷移方式,具備跨平台字序轉換和全量初始化加增量 merge 的功能,非常適用於異構 OS 跨平台遷移,成為數據庫實施人員中公認的大數據量跨平台遷移的最佳選擇。
傳統的 TTS 傳輸表空間要求數據由源端到目標端傳輸的整個過程中,表空間必須置於 read only 模式,嚴重影響業務可用性。XTTS 方式可以在業務正常運行的情況下,進行物理全量初始化,增量 block 備份,數據高低字節序轉碼,增量 block 應用,保持目標端與源端數據的同步,整個過程不影響源端數據庫使用。在最后的增量 block 應用完畢后,利用停機窗口進行數據庫切換,顯著地減少了停機時間。
XTTS 技術主要通過 DBMS_FILE_TRANSFER、RMAN 備份、手工 XTTS 遷移三種方式來進行數據庫遷移:
4.1 方式一:dbms_file_transfer
DBMS_FILE_TRANSFER 包是 Oracle 提供的一個用於復制二進制數據庫文件或在數據庫之間傳輸二進制文件的程序包,在 XTTS 遷移中,利用不同的參數進行數據文件傳輸轉換完成遷移。
DBMS_FILE_TRANSFER 方式主要使用了 xttdriver.pl 腳本的以下幾個參數:
4.2 方式二:RMAN Backup
RMAN Backup 方式是基於 RMAN 備份原理,通過使用 rman-xttconvert_2.0 包提供的參數,對數據庫進行基於表空間的備份,將備份生產的備份集寫到本地或者 NFS 盤上,然后在通過 rman-xttconvert_2.0 包中包含的不同平台之間數據文件格式轉換的包對進行數據文件格式轉換,最后通過記錄的表空間 的FILE_ID 號與生產元數據的導入來完成。
RMAN Backup 方式主要使用了 xttdriver.pl 腳本的以下幾個參數:
4.3 方式三:手工 XTTS 遷移
Oracle 提供的封裝 perl 腳本僅支持目標系統 LINUX,而通過手工 XTTS 遷移的方式可以支持目標系統是 AIX、HP、SOLARIS 等 UNIX 系統,主要有如下幾個階段:
1)rman copy
rman target / <<eof run{ allocate channel c1 type disk; allocate channel c2 type disk; backup as copy datafile 18,19,20,21,22........ format '/dump1/enmo/copy/enmo_%U'; release channel c1; release channel c2; } EOF </eof
2) 數據文件格式轉換
convert from platform 'HP-UX IA (64-bit)' datafile '/dump1/ccm/vvstart_tabs.dbf' format '+FLASHDATA/ORCL/DATAFILE/vvstart_new_01.dbf';
3) 增量備份
set until scn=1850 backup incremental from scn 1000 datafile 18,19,20,21,22...... format '/dump1/enmo/incr/copy_%d_%T_%U';3;
4) 增量轉換和應用
增量轉換: sys.dbms_backup_restore.backupBackupPiece(bpname => '/dump1/enmo/incr/copy_ORCL_20160707_78ra40o7_1_1', fname => '/dump1/enmo/incr/copy_ORCL_20160707_78ra40o7_1_1_conv',handle => handle,media=> media, comment=> comment, concur=> concur,recid=> recid,stamp => stamp, check_logical => FALSE,copyno=> 1, deffmt=> 0, copy_recid=> 0,copy_stamp => 0,npieces=> 1,dest=> 0,pltfrmfr=> 4); 增量應用: sys.dbms_backup_restore.restoreBackupPiece(done => done, params => null, outhandle => outhandle,outtag => outtag, failover => failover);
三種方式的目標端數據庫版本均需要為 11.2.0.4 版本或者以上,如果在使用過程中,目標庫的版本是 11.2.0.3 或者更低,那么需要創建一個單獨的 11.2.0.4 版本數據庫作為中間庫來在目標端進行數據文件的格式轉換,而使用 DBMS_FILE_TRANSFER 包目標端的數據庫版本必須是 11.2.0.4。
5 XTTS 初始參數說明
XTTS 是基於一組 rman-xttconvert_2.0 的腳本文件包來實現跨平台的數據遷移,主要包含 Perl script xttdriver 和 xttdriver Perl 腳本。Perl script xttdriver.pl 是備份、轉換、應用的執行腳本,xtt.properties 是屬性文件,其中包含 XTTS 配置的路徑、參數。
rman-xttconvert_2.0 包參數說明如下表:
6 XTTS 遷移步驟(使用 RMAN 備份方法)
主要有以下步驟:
1)初始化參數設置;
2)將源端數據文件傳輸到目標系統;
3)轉換數據文件為目標系統的字節序;
4)在源端創建增量備份,並傳輸到目標端;
5)在目標端恢復增量備份;
6)重復多次操作4和5步驟;
7)將源端數據庫表空間設置為 READ ONLY 模式;
8)最后一次執行4和5步驟;
9)在源端導出元數據,並在目標端導入;
10)將目標端的數據庫表空間設置為 READ WRITE;
11)數據驗證。
6.1 XTTS 遷移准備階段
6.1.1 生產庫打開塊跟蹤特性
如果源庫是 11g,需要先禁用延時段特性 不然 xtts 不會將空表導入目標庫。
alter system set deferred_segment_creation=false sid='*' scope=spfile;
首先在生產庫上打開塊跟蹤功能。
alter database enable block change tracking using file '/home/oracle/xtts/block_change_tracking.log';
6.1.2 傳輸表空間前自包含檢查
首先對表空間做自包含檢查,檢查出 Index 存在自包含問題,需要重建或者最后創建:
SQL> execute dbms_tts.transport_set_check(‘DATATBS ’,true); SQL> select * from transport_set_violations;
XXXX 創建在 USERS 表空間,需要提前遷移至 DATATBS 表空間。
Drop index XXXX; CREATE INDEX XXXX ON "LUOKLE"."BI_LUOKLEINSTRUCTION" ("SENDTIME", "STATUS", "RECLUOKLE", "CREATORORGID", "CREATETIME") TABLESPACE DATATBS parallel 8; Alter index XXXX noparallel;
由於 XTTS 最后導入元數據時候不支持臨時表,所以需要提前查出系統臨時表信息。
select dbms_metadata.get_ddl('TABLE',TABLE_NAME,owner) from dba_tables where TEMPORARY='Y' and owner=XXX;
需要手工創建的臨時表有X個,以下腳本導入元數據之后手工執行。
CREATE GLOBAL TEMPORARY TABLE XXX ( "_ID" NUMBER, "STATUS" CHAR(1) ) ON COMMIT PRESERVE ROWS ;
在表空間傳輸的中,要求表空間集為自包含的,自包含表示用於傳輸的內部表空間集沒有引用指向外部表空間集。自包含分為兩種:一般自包含表空間集和完全(嚴格)自包含表空間集。
常見的以下情況是違反自包含原則的:
- 索引在內部表空間集,而表在外部表空間集(相反地,如果表在內部表空間集,而索引在外部表空間集,則不違反自包含原則);
- 分區表一部分區在內部表空間集,一部分在外部表空間集(對於分區表,要么全部包含在內部表空間集中,要么全不包含);
- 如果在傳輸表空間時同時傳輸約束,則對於引用完整性約束,約束指向的表在外部表空間集,則違反自包含約束;如果不傳輸約束,則與約束指向無關;
- 表在內部表空間集,而 lob 列在外部表空間集,則違反自包含約束。
通常可以通過系統包 DBMS_TTS 來檢查表空間是否自包含,驗證可以以兩種方式執行:非嚴格方式和嚴格方式。
以下是一個簡單的驗證過程,假定在 eygle 表空間存在一個表 eygle,其上存在索引存儲在 USERS 表空間:
SQL> create table eygle as select rownum id ,username from dba_users; SQL> create index ind_id on eygle(id) tablespace users;
以SYS用戶執行非嚴格自包含檢查(full_check=false):
執行嚴格自包含檢查(full_check=true):
反過來對於 USERS 表空間來說,非嚴格檢查也是無法通過的:
但是可以對多個表空間同時傳輸,則一些自包含問題就可以得到解決:
6.1.3 目標端創建數據庫並修改部分參數
在目標環境需要提前安裝好 GI 和 Oracle 軟件,並創建監聽、拷貝生產環境的 TNS 和新數據庫,並修改部分數據庫參數:
create directory xtts_dir as 'home/oracle/xtts/'; grant read,write on directory xtts3 to public;
調整以下參數:
alter system set "_optimizer_adaptive_cursor_sharing"=false sid='*' scope=spfile; alter system set "_optimizer_extended_cursor_sharing"=none sid='*' scope=spfile; alter system set "_optimizer_extended_cursor_sharing_rel"=none sid='*' scope=spfile; alter system set "_optimizer_use_feedback"=false sid ='*' scope=spfile; alter system set deferred_segment_creation=false sid='*' scope=spfile; alter system set event='28401 trace name context forever,level 1' sid='*' scope=spfile; alter system set resource_limit=true sid='*' scope=spfile; alter system set resource_manager_plan='force:' sid='*' scope=spfile; alter system set "_undo_autotune"=false sid='*' scope=spfile; alter system set "_optimizer_null_aware_antijoin"=false sid ='*' scope=spfile; alter system set "_px_use_large_pool"=true sid ='*' scope=spfile; alter system set audit_trail=none sid ='*' scope=spfile; alter system set "_partition_large_extents"=false sid='*' scope=spfile; alter system set "_index_partition_large_extents"= false sid='*' scope=spfile; alter system set "_use_adaptive_log_file_sync"=false sid ='*' scope=spfile; alter system set disk_asynch_io=true sid ='*' scope=spfile; alter system set db_files=2000 scope=spfile; alter profile "DEFAULT" limit PASSWORD_GRACE_TIME UNLIMITED; alter profile "DEFAULT" limit PASSWORD_LIFE_TIME UNLIMITED; alter profile "DEFAULT" limit PASSWORD_LOCK_TIME UNLIMITED; alter profile "DEFAULT" limit FAILED_LOGIN_ATTEMPTS UNLIMITED; exec dbms_scheduler.disable( 'ORACLE_OCM.MGMT_CONFIG_JOB' ); exec dbms_scheduler.disable( 'ORACLE_OCM.MGMT_STATS_CONFIG_JOB' ); BEGIN DBMS_AUTO_TASK_ADMIN.DISABLE( client_name => 'auto space advisor', operation => NULL, window_name => NULL); END; / BEGIN DBMS_AUTO_TASK_ADMIN.DISABLE( client_name => 'sql tuning advisor', operation => NULL, window_name => NULL); END; /
6.1.4 源端保留用戶信息和權限
源端保留用戶信息和權限:
spool create_user_LUOKLE.sql select 'create user '||username||' identified by values '||''''||password||''''||';' from dba_users where default_tablespace in('TEST'); spool off
角色權限的語句:
spool grant_role_priv_LUOKLE.sql select 'grant '||GRANTED_ROLE||' to '||grantee||';' from dba_role_privs where grantee in(select username from dba_users where default_tablespace in('TEST')); spool off
sys 權限的賦權語句:
spool grant_sys_priv_LUOKLE.sql select 'grant '||privilege||' to '||grantee||';' from dba_sys_privs where grantee in(select username from dba_users where default_tablespace in('TEST')); spool off
對表空間的配額權限語句:
spool unlimited_tablespace_LUOKLE.sql select 'alter user '||username||' quota unlimited on DATATBS ||';' from dba_users where default_tablespace in('TEST'); spool off
附:若后期存在用戶與其他非本用戶的對象權限問題,如 Schema A 對 Schema B 上表的訪問和操作等權限,可以使用以下語句在源庫檢索出權限,並在目標端數據庫進行賦權即可:
set line 200 set pages 0 spool grant_tab_priv.sql select 'grant ' || privilege || ' on ' || owner || '.' || table_name || ' to ' || grantee || ';' from dba_tab_privs where owner in (select username from dba_users where default_tablespace in('TEST')) or grantee in (select username from dba_users where default_tablespace in('TEST'')) and privilege in('SELECT','DELETE','UPDATE','INSERT') and grantable='NO' union select 'grant ' || privilege || ' on ' || owner || '.' || table_name || ' to ' || grantee || ' with grant option;' from dba_tab_privs where owner in (select username from dba_users where default_tablespace in('TEST')) or grantee in (select username from dba_users where default_tablespace in('TEST')) and privilege in('SELECT','DELETE','UPDATE','INSERT') and grantable='YES'; spool off
6.2 XTTS 遷移初始化階段
6.2.1 源端更改配置文件 xtt.properties
更改以下參數:
tablespaces=TEST,TEST_INDEX platformid=13 dfcopydir=/home/oracle/xtts/bak backupformat=/home/oracle/xtts/bakincr stageondest=/home/oracle/xtts/bak storageondest=+DATA/oracle11gasm/datafile backupondest=+DATA/oracle11gasm/datafile asm_home=/u01/app/grid/product/11.2.0/grid asm_sid=+ASM parallel=2 rollparallel=2 getfileparallel=2
更改配置之后,將整個 rman-xttconvert 目錄傳輸至目標端。
6.2.2 源端進行遷移初始化
在源端進行初始化,即 backup as copy 的形式備份數據文件到 /aix_xtts/bak 下。
more full_backup.sh export TMPDIR=/aix_xtts perl xttdriver.pl -p
執行腳本進行全備:
nohup sh ./full_back.sh >full_back.log &
初始化之后產生 xttplan.txt rmanconvert.cmd;
xttplan.txt 記錄了當前 SCN,也就是下次需要增量的開始 SCN;
rmanconvert.cmd 記錄了文件轉換的名字。
[oracle@oracle11gasm xtts]$ cat rmanconvert.cmd host 'echo ts::TEST'; convert from platform 'Linux x86 64-bit' datafile '/home/oracle/xtts/bak/TEST_5.tf' format '+DATA/oracle11gasm/datafile/%N_%f.xtf' parallelism 2; host 'echo ts::TEST_INDEX'; convert from platform 'Linux x86 64-bit' datafile '/home/oracle/xtts/bak/TEST_INDEX_6.tf' format '+DATA/oracle11gasm/datafile/%N_%f.xtf' parallelism 2;
6.2.3 轉換初始化文件至 ASM 中
由於使用了 NFS 不需要再次傳輸 /aix_xtts/bak,修改 xtt.properties 文件:
修改備庫 xtt.properties 文件:
增加:
asm_home=/oracle/app/grid/11.2.0.4 asm_sid=+ASM
該步驟中,我們需要在 Linux 目標端主機上完成,進行全庫的數據文件轉換,通過腳本直接將數據文件轉換到 ASM DISKGROUP 中。
注意:該轉換步驟中,我們只需要轉換我們需要傳輸的業務表空間即可,也就是 DATATBS 。
如下是全庫的轉換腳本:
more convert.sh export XTTDEBUG=1 export TMPDIR=/aix_xtts perl xttdriver.pl -c
執行腳本進行轉換:
nohup sh ./convert.sh >convert.log &
並且在目標的 storageondest 目錄下會生成經轉換后的數據文件拷貝。
日志如下:
-------------------------------------------------------------------- Parsing properties -------------------------------------------------------------------- -------------------------------------------------------------------- Done parsing properties -------------------------------------------------------------------- -------------------------------------------------------------------- Checking properties -------------------------------------------------------------------- -------------------------------------------------------------------- Done checking properties -------------------------------------------------------------------- -------------------------------------------------------------------- Performing convert -------------------------------------------------------------------- -------------------------------------------------------------------- Converted datafiles listed in: /xtts/xttnewdatafiles.txt
轉換成功之后會生成 xttnewdatafiles.txt,該文件為數據文件在 ASM MAP 關系表,即 file_id 和數據文件名對應表,增量恢復需要。
如果沒有產生需要手工創建,命令格式如下:
[oracle@oracle11gasm xtts]$ cat xttnewdatafiles.txt ::TEST 5,+DATA/oracle11gasm/datafile/test_5.xtf ::TEST_INDEX 6,+DATA/oracle11gasm/datafile/test_index_6.xtf
6.3 XTTS 遷移增量備份恢復
6.3.1 生產庫進行第一次增量備份
由於生產庫每天的歸檔極大,因此需要進行多次增量備份,並將增量備份傳輸到目標端 Linux 的新環境,並應用增量備份,其中初始化產生的 xttplan.txt 文件記錄了增量 SCN 起始位置,這里我們只需要對需要傳輸的表空間進行增量備份即可:
more do_incr.sh export TMPDIR=/aix_xtts perl xttdriver.pl –i
執行腳本進行增量備份:
nohup sh ./do_incr.sh >do_incr_1.log &
backup incremental from scn 13827379581 第一次增量備份開始的 SCN,由 -p 初始化產生;
增量8天的數據時間花費100分鍾,產生增量文件40G。
[root@ecmsdb01plk xtts]# cat xttplan.txt.new --增量備份生成新的 xttplan.txt.new 文件 DATATBS ::::14000344337 --下一次增量備份開始的 SCN [oracle@oracle11g bakincr]$ pwd /home/oracle/xtts/bakincr [oracle@oracle11g bakincr]$ ls -lrt -rw-r----- 1 oracle oinstall 49152 Apr 1 08:00 0gsv7s0v_1_1 -rw-r----- 1 oracle oinstall 49152 Apr 1 08:00 0hsv7s10_1_1
第一次增量備份之后產生的2個配置文件為 tsbkupmap.txt 和 incrbackups.txt,這兩個為增量與數據文件對應關系配置,在做增量恢復時候需要用到。
[oracle@oracle11gasm xtts]$ cat tsbkupmap.txt TEST_INDEX::6:::1=0hsv7s10_1_1 TEST::5:::1=0gsv7s0v_1_1 [oracle@oracle11gasm xtts]$ cat incrbackups.txt /home/oracle/xtts/bakincr/0hsv7s10_1_1 /home/oracle/xtts/bakincr/0gsv7s0v_1_1
通過 FTP 傳輸增量文件至目標 LINUX 環境。
ftp> put a0rj69fq_1_1 200 PORT command successful. 150 Opening data connection for a0rj69fq_1_1. 226 Transfer complete. 23119626240 bytes sent in 1395 seconds (1.618e+04 Kbytes/s) local: a0rj69fq_1_1 remote: a0rj69fq_1_1 ftp> ftp> ftp>put 9vrj66jc_1_1 200 PORT command successful. 150 Opening data connection for 9vrj66jc_1_1. 226 Transfer complete. 22823591936 bytes sent in 1381 seconds (1.614e+04 Kbytes/s) local: 9vrj66jc_1_1 remote: 9vrj66jc_1_1
兩個窗口並行傳輸,花費時間25分鍾,由於第一次增量數據較大整體消耗2個小時。
6.3.2 目標端進行第一次增量恢復
增量恢復前需要檢查 xttnewdatafiles.txt(數據文件在 ASM 中 MAP 關系表)、tsbkupmap.txt 和 incrbackups.txt(增量與數據文件對應關系配置)、xttplan.txt(下次需要增量的開始 SCN)這些配置文件是否存在,如不存在會出現報錯。
將增量備份集放置 /home/oracle/xtts/bak下,做增量恢復:
more restore_incr.sh export TMPDIR=/home/oracle/xtts perl xttdriver.pl -r
執行腳本進行增量恢復:
nohup sh ./restore_incr.sh >restore_incr.log &
第一次增量轉換加恢復40G數據耗時30分鍾。
如果在-r應用報 ORA-19638 錯誤,則需要把 xttplan.txt 使用前一次或前二次的。(因為多次的-i和-s會對 xttplan.txt 進行修改)
6.3.3 生成下次增量所需 SCN 配置文件
$ perl xttdriver.pl -s
-------------------------------------------------------------------- Parsing properties -------------------------------------------------------------------- -------------------------------------------------------------------- Done parsing properties -------------------------------------------------------------------- -------------------------------------------------------------------- Checking properties -------------------------------------------------------------------- -------------------------------------------------------------------- Done checking properties -------------------------------------------------------------------- Prepare newscn for Tablespaces: 'DATATBS ' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' Prepare newscn for Tablespaces: '' New /oraexport/xtts/xttplan.txt with FROM SCN's generated [root@ecmsdb01plk xtts]# cat xttplan.txt DATATBS ::::14000344337
生產環境執行如上命令,產生最新 xttplan.txt 文件,下次增量備份開始 SCN 為 14000344337。
6.3.4 生產庫進行第二次增量備份
生產環境進行第二次增量備份,此次增量備份一天數據:
more do_incr.sh export TMPDIR=/home/oracle/xtts perl xttdriver.pl –i
執行腳本進行增量備份:
nohup sh ./do_incr.sh >do_incr_1.log &
backup incremental from scn 14000344337 第二次增量備份開始的 SCN。
第二次增量備份一天數據耗時5分鍾。產生文件12G,通過 FTP 並行傳輸花費10分鍾,總體二次增量備份一天數據耗時20分鍾。
6.3.5 目標端進行第二次增量恢復
xttplan.txt 使用前一次的。
二次增量恢復一天數據,耗時15分鍾:
[oracle@ecmsdb01plk scripts_linux]$ perl xttdriver.pl -r -d
6.4 XTTS 正式遷移
切割准備工作示意圖
6.4.1 停止業務
業務部門停止應用程序。數據庫檢查當前會話,需要殺掉已經存在的會話。
set lines 132 pages 1111 trim on trims on spo machine_before_upgrade.txt select inst_id, machine, count(*) from gv$session where username!='SYS' group by inst_id, machine; spo off
Kill 掉任然連接到數據庫的會話:
SELECT 'kill -9 '||SPID FROM V$PROCESS WHERE ADDR IN (SELECT PADDR FROM V$SESSION WHERE USERNAME != 'SYS'); 或 select 'alter system kill session '''||sid||','||serial#||''' immediate;' from v$session where USERNAME != 'SYS';
6.4.2 生成最后一次增量備份 SCN 配置文件
$ perl xttdriver.pl -s
使用 xttdriver.pl –s生成最后一個 SCN 增量配置文件(即最后一次增量備份開始的SCN),也可以手工修改 xttplan.txt。
6.4.3 生產庫將表空間設置為只讀
將業務表空間設置為只讀模式,並開始最后一次的增量備份。
sqlplus / as sysdba alter tablespace DATAtBS read only;
6.4.4 最后一次增量備份
在源端中間環境進行最后一次增量備份:
more do_incr.sh export TMPDIR=/home/oracle/xtts perl xttdriver.pl –i 執行腳本進行備份: nohup sh ./do_incr.sh >do_incr_1.log &
按照之前每天增量備份加傳輸大概耗時30分鍾,在增量備份同時可以進行元數據的導出。
6.4.5 導出元數據(XTTS 元數據以及其他對象元數據)
在這個步驟中,我們可以並行同時導出 XTTS 的元數據以及其他的元數據,例如數據庫存儲過程,函數。觸發器等等。
導出傳輸表空間元數據命令如下:
create or replace directory xtts3 as '/oraexport/xtts/ ' exp \'/ as sysdba \' transport_tablespace=y tablespaces='DATATBS ' file=/oraexport/xtts/exp_DATATBS_xtts.dmp log=/oraexport/xtts/exp_DATATBS_xtts.log STATISTICS=none parallel=8 expdp \'/ as sysdba\' dumpfile=tts.dmp directory=xtts_dir logfile=expdp_xtts.log transport_tablespaces=TEST,TEST_INDEX exclude=STATISTICS;
導出元數據耗時2分鍾。
導出其他對象數據如下:
expdp \'/ as sysdba\' directory=xtts_dir dumpfile=expdp_LUOKLE_meta.dmp logfile=expdp_LUOKLE_meta.log CONTENT=metadata_only SCHEMAS=LUOKLE parallel=2;
導出其他數據耗時15分鍾。
導出完成之后,將 dmp 文件傳輸到 Linux。
6.4.6 最后一次應用增量備份
將備份集放置 /oradata2 下,做增量恢復:
more restore_incr.sh export TMPDIR=/home/oracle/xtts perl xttdriver.pl -r -d 執行腳本進行增量恢復: nohup sh ./restore_incr.sh >restore_incr.log &
根據之前增量恢復一天數據大概耗時15分鍾。
6.4.7 導入 XTTS 元數據
通過如下命令將 xtts 表空間元數據導入到目標新庫中:
create or replace directory xtts_dir as '/home/oracle/xtts/'; impdp \'/ as sysdba\' dumpfile=expdp_tts.dmp directory=xtts_dir transport_tablespace=y datafiles='+DATA/ORACLE11GASM/DATAFILE/test_5.xtf,+DATA/ORACLE11GASM/DATAFILE/test_index_6.xtf';
根據之前測試結果導入時間為10分鍾左右。
6.4.8 目標端新庫將表空間設置為讀寫模式
將業務表空間設置為可讀寫模式:
sqlplus / as sysdba alter tablespace DATATBS read write;
6.4.9 目標端新庫導入其他對象元數據
impdp \'/ as sysdba\' dumpfile=expdp_LUOKLE_meta.dmp directory=xtts_dir
STATISTICS 如果不使用之前統計信息可用排除,最后收集。
根據之前測試耗時15分鍾左右,XTTS 已完成表空間遷移。
7 XTTS 遷移后檢查
7.1 更改用戶默認表空間
更改用戶默認表空間,將用戶默認表空間設置與源數據庫保持一致:
@default_tablespace.sql 源端執行: spool default_tablespace.sql select 'alter user '||username||' default tablespace '||default_tablespace||';' from dba_users where default_tablespace in(‘DATATBS ’); spool off 添加表空間配額權限: @unlimited_tablespace.sql 源庫: select 'alter user '||username||' quota unlimited on '|| default_tablespace||';' from dba_users where default_tablespace in (‘DATATBS ’);
7.2 數據庫對象並行重編譯
exec utl_recomp.recomp_parallel(32); set echo off feedback off timing off verify off set pagesize 0 linesize 500 trimspool on trimout on Set heading off; set feedback off; set echo off; Set lines 999; spool compile.sql select 'alter '|| decode(object_type,'SYNONYM',decode(owner,'PUBLIC','PUBLIC SYNONYM '||object_name, 'SYNONYM '||OWNER||'.'||OBJECT_NAME)||' compile;', decode(OBJECT_TYPE ,'PACKAGE BODY','PACKAGE',OBJECT_TYPE)|| ' '||owner||'.'||object_name||' compile '|| decode(OBJECT_TYPE ,'PACKAGE BODY','BODY;',' ;')) from dba_objects where status<>'VALID' order by owner,OBJECT_NAME; spool off @compile.sql
正式環境沒有無效對象。
7.3 數據庫對象數據比對
運行數據庫對比腳本,通過創建 dblink,運行相關的數據庫對象比對腳本。這里我們主要比對了存儲過程,函數,觸發器,試圖,索引,表等等。
創建到生產環境 DB LINK
CREATE DATABASE LINK TEST_COMPARE CONNECT TO SYSTEM IDENTIFIED BY password xxx USING 'xxxx:1521/xxxx';
使用如下腳本對比數據庫中對象個數:
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM DBA_OBJECTS@TEST_COMPARE WHERE OBJECT_NAME NOT LIKE 'BIN%' AND OBJECT_NAME NOT LIKE 'SYS_%' AND OWNER IN ('LUOKLE') MINUS SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM DBA_OBJECTS WHERE OBJECT_NAME NOT LIKE 'BIN%' AND OBJECT_NAME NOT LIKE 'SYS_%' AND OWNER IN ('LUOKLE'); 或 源庫: select object_type,count(*) from dba_objects where owner in (select username from 源庫) group by object_type; 目標: select object_type,count(*) from dba_objects where owner in (select username from 目標庫) group by object_type;
如果索引缺失可能是由於沒有存放在傳輸的表空間所以需要重新創建,而缺失的表可能是臨時表,需要手工創建。
使用如下腳本進行創建:
CREATE INDEX "LUOKLE"."IDX_XXX" ON "LUOKLE"."BI_XXXX" TABLESPACEDATATBS parallel 8; Alter index "LUOKLE"."IDX_XX" noparallel; CREATE GLOBAL TEMPORARY TABLE "LUOKLE"."TEMP_PAY_BATCH_CREATE_INSTR" ( "BATCH_ID" NUMBER, "STATUS" CHAR(1) ) ON COMMIT PRESERVE ROWS ;
使用 hash 函數進行數據對比
兩邊分別創建存放 hash 數據的表
create table system.get_has_value (dbname varchar2(20),owner varchar2(30),table_name varchar2(100),value varchar2(100),error varchar2(2000));
創建需要驗證的表:
create sequence system.sequence_checkout_table start with 1 increment by 1 order cycle maxvalue 10 nocache; CREATE TABLE SYSTEM.checkout_table as select sys_context('USERENV', 'INSTANCE_NAME') dbnme,owner,table_name, system.sequence_checkout_table.NEXTVAL groupid from dba_tables where owner='LUOKLE'
結果顯示:
1 SELECT owner, groupid, COUNT (*) 2 FROM SYSTEM.checkout_table 3* GROUP BY owner, groupid,dbnme Order by owner,groupid 14:05:21 SQL> SELECT owner, groupid, COUNT (*) 14:05:31 2 FROM SYSTEM.checkout_table 14:05:32 3 GROUP BY owner, groupid,dbnme Order by owner,groupid; OWNER GROUPID COUNT(*) ------------------------------ ---------- ---------- LUOKLE 1 32 LUOKLE 2 31 LUOKLE 3 31 LUOKLE 4 31 LUOKLE 5 31 LUOKLE 6 31 LUOKLE 7 31 LUOKLE 8 31 LUOKLE 9 31 LUOKLE 10 31 創建 hash 函數 grant select on sys.dba_tab_columns to system; CREATE OR REPLACE PROCEDURE SYSTEM.get_hv_of_data ( avc_owner VARCHAR2, avc_table VARCHAR2) AS lvc_sql_text VARCHAR2 (30000); ln_hash_value NUMBER; lvc_error VARCHAR2 (100); BEGIN SELECT 'select /*+parallel(a,25)*/sum(dbms_utility.get_hash_value(' || column_name_path || ',0,power(2,30)) ) from ' || owner || '.' || table_name || ' a ' INTO LVC_SQL_TEXT FROM (SELECT owner, table_name, column_name_path, ROW_NUMBER () OVER (PARTITION BY table_name ORDER BY table_name, curr_level DESC) column_name_path_rank FROM ( SELECT owner, table_name, column_name, RANK, LEVEL AS curr_level, LTRIM ( SYS_CONNECT_BY_PATH (column_name, '||''|''||'), '||''|''||') column_name_path FROM ( SELECT owner, table_name, '"' || column_name || '"' column_name, ROW_NUMBER () OVER (PARTITION BY table_name ORDER BY table_name, column_name) RANK FROM dba_tab_columns WHERE owner = UPPER (avc_owner) AND table_name = UPPER (avc_table) AND DATA_TYPE IN ('TIMESTAMP(3)', 'INTERVAL DAY(3) TO SECOND(0)', 'TIMESTAMP(6)', 'NVARCHAR2', 'CHAR', 'BINARY_DOUBLE', 'NCHAR', 'DATE', 'RAW', 'TIMESTAMP(6)', 'VARCHAR2', 'NUMBER') ORDER BY table_name, column_name) CONNECT BY table_name = PRIOR table_name AND RANK - 1 = PRIOR RANK)) WHERE column_name_path_rank = 1; EXECUTE IMMEDIATE lvc_sql_text INTO ln_hash_value; lvc_sql_text := 'insert into system.get_has_value(owner,table_name,value) values(:x1,:x2,:x3)'; EXECUTE IMMEDIATE lvc_sql_text USING avc_owner, avc_table, ln_hash_value; commit; DBMS_OUTPUT.put_line ( avc_owner || '.' || avc_table || ' ' || ln_hash_value); EXCEPTION WHEN NO_DATA_FOUND THEN lvc_error := 'NO DATA FOUND'; lvc_sql_text := 'insert into system.get_has_value(owner,table_name,error) values(:x1,:x2,:x3)'; EXECUTE IMMEDIATE lvc_sql_text USING avc_owner, avc_table, lvc_error; commit; WHEN OTHERS THEN lvc_sql_text := 'insert into system.get_has_value(owner,table_name,value) values(:x1,:x2,:x3)'; EXECUTE IMMEDIATE lvc_sql_text USING avc_owner, avc_table, SQLERRM; commit; END; / sqlplus system/oracle<<EOF set heading off linesize 170 pagesize 0 feedback off echo off trimout on trimspool on termout off verify of exit EOF nohup ./check_source.sh LUOKLE 1 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 2 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 3 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 4 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 5 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 6 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 7 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 8 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 9 >./source_LUOKLE_cd_1.log 2>&1 & nohup ./check_source.sh LUOKLE 10 >./source_LUOKLE_cd_1.log 2>&1 & checkdata_source.sh date sqlplus system/oracle<<EOF set heading off linesize 170 pagesize 0 feedback off spool source_check_$1_$2.sql SELECT 'exec system.get_hv_of_data(''' || owner || ''',''' || table_name || ''')' FROM system.checkout_table WHERE owner = UPPER ('$1') and groupid=$2 AND table_name NOT IN (SELECT table_name FROM dba_tables WHERE owner = UPPER ('$1') AND iot_type IS NOT NULL) AND table_name IN (SELECT table_name FROM ( SELECT table_name, COUNT (*) FROM dba_tab_columns WHERE owner = UPPER ('$1') AND DATA_TYPE IN ('TIMESTAMP(3)', 'INTERVAL DAY(3) TO SECOND(0)', 'TIMESTAMP(6)', 'NVARCHAR2', 'CHAR', 'BINARY_DOUBLE', 'NCHAR', 'DATE', 'RAW', 'VARCHAR2', 'NUMBER') GROUP BY table_name HAVING COUNT (*) > 0)) ORDER BY table_name; spool off set serveroutput on @source_check_$1_$2.sql exit; EOF date 運行 hash 計算函數腳本,在LINUX環境對 LUOKLE 下所有表進行 hash 計算耗時30分鍾,總共311張表,有52張表沒有計算出 hash 經分析發現這些表為空表。 SQL> select count(*) from LUOKLE.XXXX; COUNT(*) ---------- 0
7.4 數據庫對象間權限比對處理
對比源庫和目標庫數據庫的對象級別間權限,如若權限不一致建議將源庫跑出的 grant_tab_privs.log 到目標端執行。
復核對象上的 select 和 DML 權限賦予給用戶 @grant_tab_privs.sql 源庫: select 'grant ' || privilege || ' on ' || owner || '.' || table_name || ' to ' || grantee || ';' from dba_tab_privs where (grantee in(select username from dba_users where default_tablespace in(‘DATATBS ’)) or owner in(select username from dba_users where default_tablespace in(DATATBS ))) and privilege in('SELECT','DELETE','UPDATE','INSERT') and grantable='NO' union select 'grant ' || privilege || ' on ' || owner || '.' || table_name || ' to ' || grantee || ' with grant option;' from dba_tab_privs where (grantee in(select username from dba_users where default_tablespace in(DATATBS )) or owner in(select username from dba_users where default_tablespace in(DATATBS ))) and privilege in('SELECT','DELETE','UPDATE','INSERT') and grantable='YES';
7.5 收集統計信息
為了防止同時收集統計信息,造成系統資源的消耗,建議提前關閉后台自動收集統計信息的任務。
exec DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'auto optimizer stats collection',operation => NULL,window_name => NULL);
查看柱狀圖信息:
select count(*),owner,table_name,column_name from dba_tab_histograms group by owner,table_name,column_name having count(*) > 2;
手工運行收集腳本:
exec DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','TRUE');設置並發收集模式 exec dbms_stats.gather_database_stats( estimate_percent =>dbms_stats.AUTO_SAMPLE_SIZE, ///// for all columns size repeat METHOD_OPT=>'FOR ALL COLUMNS SIZE 1', options=> 'GATHER',degree=>8, granularity =>’all’, cascade=> TRUE ); select * from dba_scheduler_jobs where schedule_type = 'IMMEDIATE' and state = 'RUNNING';
收集數據字典統計信息:
exec DBMS_STATS.GATHER_DICTIONARY_STATS(degree=>16);
固定對象的統計信息:
EXECUTE DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;
開啟默認收集
exec DBMS_AUTO_TASK_ADMIN.ENABLE(client_name => 'auto optimizer stats collection',operation => NULL,window_name => NULL); exec DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','false');
以下為測試過程:
13:23:41 SQL> select count(*),owner,table_name,column_name from dba_tab_histograms 13:23:45 2 where owner='LUOKLE' 13:23:46 3 group by owner,table_name,column_name 13:23:46 4 having count(*) > 2; no rows selected Elapsed: 00:00:00.10 13:28:06 SQL> exec dbms_stats.gather_database_stats(estimate_percent =>dbms_stats.AUTO_SAMPLE_SIZE,METHOD_OPT=>'FOR ALL COLUMNS SIZE 1',options=> 'GATHER',degree=>8, granularity =>'all',cascade=> TRUE); PL/SQL procedure successfully completed. Elapsed: 00:26:51.34 13:55:05 SQL>
全庫統計信息收集耗時26分鍾
13:57:14 SQL> exec DBMS_STATS.GATHER_DICTIONARY_STATS(degree=>16); PL/SQL procedure successfully completed. Elapsed: 00:00:18.94
7.6 修改 job 參數
show parameter job_queue_processes; alter system set job_queue_processes=100 scope=both;
8 XTTS 遷移測試耗時(20T)
9 XTTS 遷移測試問題記錄
expdp \'/ as sysdba\' directory=xtts dumpfile=expdp_LUOKLE_meta0822.dmp logfile=expdp_LUOKLE_meta0822.log CONTENT=metadata_only SCHEMAS=LUOKLE 15:06 開始到出 ORA-39014: One or more workers have prematurely exited. ORA-39029: worker 1 with process name "DW00" prematurely terminated ORA-31671: Worker process DW00 had an unhandled exception. ORA-04030: out of process memory when trying to allocate 3704 bytes (kkoutlCreatePh,kkotbi : kkotbal) ORA-06512: at "SYS.KUPW$WORKER", line 1887 ORA-06512: at line 2
在做元數據導出時候后台報大量 ORA-04030 錯誤,經過分析為 AMM 問題,通過關閉 AMM 手工管理內存解決。
10g 的 sga_target 設置為0
Errors in file /oracle/app/oracle/diag/rdbms/LUOKLE/orcl1/trace/orcl1_ora_13107324.trc (incident=28001): ORA-04030: out of process memory when trying to allocate 32808 bytes (TCHK^cadd45dc,kggec.c.kggfa)
經過分析發現 AIX stack 設置偏小導致,修改限制解決。
ERROR IN CONVERSION ORA-19624: operation failed, retry possible ORA-19505: failed to identify file "/aix_xtts/oradata2/f8rdl6vi_1_1" ORA-27037: unable to obtain file status Linux-x86_64 Error: 2: No such file or directory Additional information: 3 ORA-19600: input file is backup piece (/aix_xtts/oradata2/f8rdl6vi_1_1) ORA-19601: output file is backup piece (/aix_xtts/incr/xib_f8rdl6vi_1_1_6_8_10_12_14_16_18_20_22_) CONVERTED BACKUP PIECE/aix_xtts/incr/xib_f8rdl6vi_1_1_6_8_10_12_14_16_18_20_22_ PL/SQL procedure successfully completed. ERROR IN CONVERSION ORA-19624: operation failed, retry possible ORA-19505: failed to identify file "/aix_xtts/oradata2/f9rdl70m_1_1" ORA-27037: unable to obtain file status Linux-x86_64 Error: 2: No such file or directory Additional information: 3 ORA-19600: input file is backup piece (/aix_xtts/oradata2/f9rdl70m_1_1) ORA-19601: output file is backup piece (/aix_xtts/incr/xib_f9rdl70m_1_1_7_9_11_13_15_17_19_21_23_) CONVERTED BACKUP PIECE/aix_xtts/incr/xib_f9rdl70m_1_1_7_9_11_13_15_17_19_21_23_
經過分析發現增量備份沒有放在對應目錄導致。
failed to create file "/xtts/incr/xib_f9rdl70m_1_1_7_9_11_13_15_17_19_21_23_" ORA-27040: file create error, unable to create file Linux-x86_64 Error: 13: Permission denied Additional information: 1 ORA-19600: input file is backup piece (/xtts/oradata2/f9rdl70m_1_1) ORA-19601: output file is backup piece (/xtts/incr/xib_f9rdl70m_1_1_7_9_11_13_15_17_19_21_23_) CONVERTED BACKUP PIECE/xtts/incr/xib_f9rdl70m_1_1_7_9_11_13_15_17_19_21_23_ PL/SQL procedure successfully completed. ERROR IN CONVERSION ORA-19624: operation failed, retry possible ORA-19504: failed to create file "/xtts/incr/xib_f8rdl6vi_1_1_6_8_10_12_14_16_18_20_22_" ORA-27040: file create error, unable to create file Linux-x86_64 Error: 13: Permission denied Additional information: 1 ORA-19600: input file is backup piece (/xtts/oradata2/f8rdl6vi_1_1) ORA-19601: output file is backup piece (/xtts/incr/xib_f8rdl6vi_1_1_6_8_10_12_14_16_18_20_22_) CONVERTED BACKUP PIECE/xtts/incr/xib_f8rdl6vi_1_1_6_8_10_12_14_16_18_20_22_
NFS 目錄權限問題導致不行讀寫,修改權限解決。
NFS 問題:
mount: 1831-008 giving up on: 192.168.1.100:/xtts vmount: Operation not permitted. # nfso -p -o nfs_use_reserved_ports=1 Setting nfs_use_reserved_ports to 1 Setting nfs_use_reserved_ports to 1 in nextboot file # mount -o cio,rw,bg,hard,nointr,rsize=32768,wsize=32768,proto=tcp,noac,vers=3,timeo=600 10.20.28.21:/xtts /aix_xtts
10 總結
XTTS 支持跨平台跨版本遷移,操作起來比較方便,由於停機時間較短,可以較輕松完成遷移工作,在大數據量的跨平台跨版本遷移場景中,建議作為首選方案。
建議在做 XTTS 遷移的時候減少批次,批次越多,增量備份的數據越少,數據越少,最后停機時間越短,但是這個過程如果做太多就越容易出錯。一般使用一次增量備份再做一次正式遷移,甚至初始化后直接做正式遷移。
11 附錄 - xttdriver.pl 腳本使用說明
詳見:11G - Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (文檔 ID 1389592.1)