摘要
最近由於工作需要,花時間研究了一下Oracle CDC功能和LogMiner工具,希望能找到一種穩定、高效的技術來實現Oracle增量數據抽取功能。以下是個人的部分學習總結和部署實踐。
1. Oracle CDC 簡介
很多人都認為,只要是涉及到數據庫數據復制和增量數據抽取,都是需要購買收費軟件的。實際上,我們通過Oracle提供的CDC和LogMiner等免費工具也能實現數據庫數據復制和增量數據抽取,各種數據復制軟件只是使得獲取增量數據更加便捷,或者是可以支持更多的擴展功能(例如:異構數據庫之間的同步,ETL過程的數據清洗、裝換),但實際Oracle本身是支持CDC機制,只是很少有人關注,操作起來也有些復雜,而且據傳言並不穩定,常常見到論壇上爆出一些莫名其妙的問題。
Oracle11gR2提供給我們以下幾種CDC機制:
1.1 Synchronous Change Data Capture Configuration(同步復制)

原理很簡單,原表、目標表必須是同一個庫,采用觸發器的機制(設置同步CDC后,並看不到觸發器,但實際運行機理還是觸發器的機制)將原表內容復制到另一個目標表。這個機制就不多說了,和自己給表建觸發器沒什么太大差別。
1.2 Asynchronous HotLog Configuration(異步在線日志CDC)

這個過程已經沒有觸發器了,而是使用Redo Log,但是使用在線日志,並不是歸檔日志。並且原表、目標表仍然必須是同一個庫。這種模式是相對簡單的,同時這種模式是在Oracle 10以上才產生的,9i是沒有這個機制的。
1.3 Asynchronous Distributed HotLog Configuration(異步分布式CDC)

實際這個模式是對異步在線日志CDC的一種優化,也比較容易理解,就是加入了DB-LINK機制,使原表、目標表不在同一個數據庫。實際是和異步在線日志CDC沒有什么本質區別。
1.4 Asynchronous Autolog Online Change Data Capture Configuration(異步在線日志復制CDC)

異步在線日志復制CDC模式就要高級很多了,使用Standby Redo Log(熱備數據庫日志),實際就是使用Oracle的熱備機制,將日志寫入了熱備數據庫,目標表就可以建立在熱備庫上,這對主數據庫性能影響就進一步降低。
1.5 Asynchronous AutoLog Archive Change Data Capture Configuration(歸檔日志CDC)

歸檔日志CDC模式是最完美的模式,但是需要有機制可以獲取歸檔日志(並行文件系統技術),然后在目標端分析歸檔日志進行變化數據處理,這種模式理論上來講,幾乎可以完全不影響原數據庫的性能。
坦白來說,我對Oracle理解並不深,只是為了解決特定的幾個問題多看了一點,在現實工作中遇到類似問題需要解決的,或對技術痴狂的同學可以研究一下,我貼上了4種模式具體的設置步驟,雖然是英文的,但是還是非常明確的。(我比較推薦使用第二種,因為設置比較簡單,性能上也屬於中規中矩,如果沒有什么特別要求,可以采用異步在線日志CDC。
以下是我對異步在線日志CDC環境的部署測試。
2. 異步在線日志CDC環境部署
2.1 環境配置准備
(1)確認數據庫版本
SQL> select * from v$version;BANNER--------------------------------------------------------------------------------Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit ProductionPL/SQL Release 11.2.0.1.0 - ProductionCORE 11.2.0.1.0 ProductionTNS for Linux: Version 11.2.0.1.0 - ProductionNLSRTL Version 11.2.0.1.0 - Production
(2)配置數據庫參數
SQL> alter system set streams_pool_size=50m;System altered.SQL> alter system set java_pool_size=50m;System altered.SQL> alter system set undo_retention=3600;System altered.SQL> show parameter streams_poolNAME TYPE VALUE------------------------------------ ----------- ------------------------------streams_pool_size big integer 52MSQL> show parameter java_poolNAME TYPE VALUE------------------------------------ ----------- ------------------------------java_pool_size big integer 52MSQL> show parameter undo_reNAME TYPE VALUE------------------------------------ ----------- ------------------------------undo_retention integer 3600
(3)開啟歸檔及補充日志
SQL> archive log listDatabase log mode Archive ModeAutomatic archival EnabledArchive destination USE_DB_RECOVERY_FILE_DESTOldest online log sequence 487Next log sequence to archive 489Current log sequence 489SQL> alter database force logging;Database altered.SQL> alter database add supplemental log data;Database altered.SQL> select LOG_MODE,FORCE_LOGGING,SUPPLEMENTAL_LOG_DATA_MIN from v$database;LOG_MODE FOR SUPPLEME------------ --- --------ARCHIVELOG YES YES
(4)准備測試表employee_info
SQL> create table employee_info(n number,name varchar(20),address varchar(150),department varchar(120),organization varchar(150)) tablespace datafile1;Table created.SQL> insert into employee_info values(1, 'bendsha', 'lianhang road, shanghai, China', 'AnyBackup', 'EISOO');1 row created.SQL> insert into employee_info values(2, 'bendsha', 'lianhang road, shanghai, China', 'AnyBackup', 'EISOO');1 row created.
2.2 創建發布者和訂閱者
(1)創建發布者並授權
SQL> create tablespace cdc_datafile datafile '/u01/app/oracle/orcl/cdc_datafile.dbf' size 1G;Tablespace created.SQL> create user cdc_publisher identified by cdc_publisher default tablespace cdc_datafile temporary tablespace temp;User created.SQL> grant create session TO cdc_publisher;Grant succeeded.SQL> grant create table TO cdc_publisher;Grant succeeded.SQL> grant create sequence TO cdc_publisher;Grant succeeded.SQL> grant create procedure TO cdc_publisher;Grant succeeded.SQL> grant create any job TO cdc_publisher;Grant succeeded.SQL> grant execute_catalog_role TO cdc_publisher;Grant succeeded.SQL> grant select_catalog_role TO cdc_publisher;Grant succeeded.SQL> grant execute ON dbms_cdc_publish TO cdc_publisher;Grant succeeded.SQL> grant execute ON dbms_lock TO cdc_publisher;Grant succeeded.SQL> grant unlimited tablespace TO cdc_publisher;Grant succeeded.SQL> execute dbms_streams_auth.grant_admin_privilege('CDC_PUBLISHER');PL/SQL procedure successfully completed.SQL> grant all on backupuser.employee_info to cdc_publisher;Grant succeeded.
(2)創建訂閱者並授權
SQL> create user cdc_subscriber identified by cdc_subscriber default tablespace cdc_datafile temporary tablespace temp;User created.SQL> grant create session TO cdc_subscriber;Grant succeeded.
2.3 發布/訂閱具體數據
(1)發布:准備源表(Source Table)
SQL>conn cdc_publisher/cdc_publisherBEGINDBMS_CAPTURE_ADM.PREPARE_TABLE_INSTANTIATION(TABLE_NAME => 'backupuser.employee_info');END;Connected.SQL> 2 3 4 /PL/SQL procedure successfully completed.
(2)發布:創建變更集(Data Set)
SQL>conn cdc_publisher/cdc_publisherBEGINDBMS_CDC_PUBLISH.CREATE_CHANGE_SET(change_set_name => 'cdc_employee_info_cs',description => 'Change set for backupuser.employee_info info',change_source_name => 'HOTLOG_SOURCE',stop_on_ddl => 'y');END;Connected.SQL> 2 3 4 5 6 7 8 9 /PL/SQL procedure successfully completed.
(3)發布:創建變更表(Change Table)
SQL>conn cdc_publisher/cdc_publisherBEGINDBMS_CDC_PUBLISH.CREATE_CHANGE_TABLE(owner => 'cdc_publisher',change_table_name => 'employee_info_ct',change_set_name => 'cdc_employee_info_cs',source_schema => 'backupuser',source_table => 'employee_info',column_type_list =>'n number,name varchar(20),address varchar(150)',capture_values => 'both',rs_id => 'y',row_id => 'n',user_id => 'n',timestamp => 'n',object_id => 'n',source_colmap => 'n',target_colmap => 'y',options_string =>'');END;19 /PL/SQL procedure successfully completed.
(4)發布:激活變更集(Data Set)
SQL>conn cdc_publisher/cdc_publisherBEGINDBMS_CDC_PUBLISH.ALTER_CHANGE_SET(change_set_name => 'cdc_employee_info_cs',enable_capture => 'y');END;Connected.SQL> 2 3 4 5 6 /PL/SQL procedure successfully completed.
(5)授權給訂閱者
SQL>conn cdc_publisher/cdc_publisherGRANT SELECT ON cdc_publisher.employee_info_ct TO cdc_subscriber;conn / as sysdbaGRANT CREATE TABLE TO cdc_subscriber;GRANT CREATE SESSION TO cdc_subscriber;GRANT CREATE VIEW TO cdc_subscriber;- GRANT UNLIMITED TABLESPACE TO cdc_subscriber;
Grant succeeded.
(6)訂閱:創建訂閱集
SQL>conn cdc_subscriber/cdc_subscriberBEGINDBMS_CDC_SUBSCRIBE.CREATE_SUBSCRIPTION(change_set_name => 'cdc_employee_info_cs',description => 'Change data for employee_info',subscription_name => 'employee_info_sub');END;Connected.SQL> 2 3 4 5 6 7 /PL/SQL procedure successfully completed.
(7)訂閱:開始訂閱表信息
SQL>conn cdc_subscriber/cdc_subscriberBEGINDBMS_CDC_SUBSCRIBE.SUBSCRIBE(subscription_name => 'employee_info_sub',source_schema => 'backupuser',source_table => 'employee_info',column_list => 'n,name,address',subscriber_view => 'employee_info_view');END;Connected.SQL> 2 3 4 5 6 7 8 9 /PL/SQL procedure successfully completed.
(8)訂閱:激活訂閱
SQL>conn cdc_subscriber/cdc_subscriberBEGINDBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION(subscription_name => 'employee_info_sub');END;Connected.SQL> 2 3 4 5 /PL/SQL procedure successfully completed.
(9)訂閱:擴展訂閱窗口
SQL>conn cdc_subscriber/cdc_subscriberBEGINDBMS_CDC_SUBSCRIBE.EXTEND_WINDOW(subscription_name => 'employee_info_sub');END;Connected.SQL> 2 3 4 5 /PL/SQL procedure successfully completed.
(10)訂閱:查看訂閱視圖內容
SQL>conn cdc_subscriber/cdc_subscriberConnected.SQL> select * from employee_info_view;no rows selected
2.4 測試發布/訂閱
(1)源表employee_info變更
SQL>conn backupuser/backupuser123insert into employee_info values(1, 'bendsha', 'lianhang road, shanghai, China', 'SmartData', 'SmartDB');insert into employee_info values(2, 'bendsha', 'lianhang road, shanghai, China', 'SmartData', 'SmartDB');insert into employee_info values(3, 'bendsha', 'lianhang road, shanghai, China', 'SmartData', 'SmartDB');update employee_info set name = 'zhuzi' where n = 2;delete from employee_info where n = 1;Connected.SQL>1 row created.SQL>1 row created.SQL>1 row created.SQL>1 row updated.SQL>1 row deleted.SQL> commit;Commit complete.
(2)查看數據發布情況
SQL>conn cdc_publisher/cdc_publisherConnected.SQL> select OPERATION$,n,name,address from employee_info_ct;OP N NAME-- ---------- --------------------ADDRESS--------------------------------------------------------------------------------I 1 bendshalianhang road, shanghai, ChinaI 2 bendshalianhang road, shanghai, ChinaI 3 bendshalianhang road, shanghai, ChinaOP N NAME-- ---------- --------------------ADDRESS--------------------------------------------------------------------------------UO 2 bendshalianhang road, shanghai, ChinaUN 2 zhuzilianhang road, shanghai, ChinaD 1 bendshalianhang road, shanghai, China6 rows selected.
(3)查看數據訂閱情況
SQL>conn cdc_subscriber/cdc_subscriberBEGINDBMS_CDC_SUBSCRIBE.EXTEND_WINDOW(subscription_name => 'employee_info_sub');END;Connected.SQL> 2 3 4 5 /PL/SQL procedure successfully completed.SQL> select OPERATION$,n,name,address from employee_info_view;OP N NAME-- ---------- --------------------ADDRESS--------------------------------------------------------------------------------I 1 bendshalianhang road, shanghai, ChinaI 2 bendshalianhang road, shanghai, ChinaI 3 bendshalianhang road, shanghai, ChinaOP N NAME-- ---------- --------------------ADDRESS--------------------------------------------------------------------------------UO 2 bendshalianhang road, shanghai, ChinaUN 2 zhuzilianhang road, shanghai, ChinaD 1 bendshalianhang road, shanghai, China6 rows selected.
(4)清除變更數據集
SQL>conn cdc_subscriber/cdc_subscriberBEGINDBMS_CDC_SUBSCRIBE.PURGE_WINDOW(subscription_name => 'employee_info_sub');END;Connected.SQL> 2 3 4 5 /PL/SQL procedure successfully completed.SQL> select OPERATION$,n,name,address from employee_info_view;no rows selected
(5)刪除發布數據
SQL> conn cdc_publisher/cdc_publisherConnected.SQL> truncate table employee_info_ct;Table truncated.SQL> select OPERATION$,n,name,address from employee_info_ct;no rows selected
3. 常見問題解決方法
3.1 ORA-31466: 未找到發布內容
執行訂閱表信息時,提示ORA-31466:未找到發布內容,排查發現是沒有將變更表cdc_employee_info的查詢權限賦予訂閱者用戶cdc_subscriber導致。
解決方法:
SQL> conn cdc_publisher/cdc_publisherConnected.SQL> grant select on cdc_employee_info to cdc_subscriber;Grant succeeded.
3.2 激活訂閱之后,對源表進行操作,捕獲不到數據
我一開始遇到這個問題是監控系統用戶SYS用戶的employee_info表,沒有出現任何異常,就是捕獲不到數據,后來我替換給backupuser用戶的employee_info表,按照以上步驟操作,就能正常捕獲到數據了,官網也沒查到相關的文檔說明,很奇怪,還需要進一步研究。
4. 參考文檔
Oracle 10.2 CDC:
http://docs.oracle.com/cd/B19306_01/server.102/b14223/cdc.htm
DBMS_CDC_SUBSCRIBE:
http://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_cdcsub.htm#ARPLS024
