背景 最近在負責公司數據Oracle轉PG;老平臺資料庫:Oracle11g;新平臺資料庫:PostgreSQL12。由於平臺統計規則有變動;所以正在推廣的游戲數據無法全部遷移過來;只能在老平臺上運行。而支付數據介面升級;統一進入新平臺數據PG。需要將部分支付數據由PostgreSQL同步到Orac ...
背景
最近在負責公司數據Oracle轉PG;老平臺資料庫:Oracle11g;新平臺資料庫:PostgreSQL12。由於平臺統計規則有變動;所以正在推廣的游戲數據無法全部遷移過來;只能在老平臺上運行。而支付數據介面升級;統一進入新平臺數據PG。需要將部分支付數據由PostgreSQL同步到Oracle。
簡而言之:PostgreSQL增量同步表到Oracle。首先聲明我不是反“去IOE”潮流。我想到兩種方案
- 採用OGG 可以參考 OGG For Oracle To PostgreSQL
- 採用外部表+腳本/存儲過程
1、下載地址 http://www.oracle.com/technetwork/database/database-technologies/instant-client/overview/index.html 2、 安裝步驟 2.1 創建安裝目錄 [root@Postgres201 ~]# mkdir -p /u01/app/ [root@Postgres201 ~]# cd /u01/app/ 2.2 上傳軟體包並解壓 [root@Postgres201 app]# unzip instantclient-basic-linux.x64-11.2.0.4.0.zip [root@Postgres201 app]# unzip instantclient-sqlplus-linux.x64-11.2.0.4.0.zip [root@Postgres201 app]# unzip instantclient-sdk-linux.x64-11.2.0.4.0.zip [root@Postgres201 app]# mv instantclient_11_2/ oracle [root@Postgres201 app]# cd oracle 2.3 配置網路文件 [root@Postgres201 app]# cd oracle [root@Postgres201 oracle]# mkdir -p network/admin [root@Postgres201 oracle]# cd network/admin/ [root@Postgres201 admin]# vi tnsnames.ora ora221 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.221)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = orcl) ) ) 2.4 配置用戶環境變數 export ORACLE_HOME=/u01/app/oracle export TNS_ADMIN=$ORACLE_HOME/network/admin export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH export PATH=$ORACLE_HOME:$PATH
1、下載地址 http://pgxn.org/dist/oracle_fdw/ 2、安裝步驟 [root@Postgres201 opt]# unzip oracle_fdw-2.0.0.zip [root@Postgres201 opt]# cd oracle_fdw-2.0.0 #載入環境變數後執行 pg_config是否在對應PGHOME/bin目錄下。編譯後會在對應的目錄下麵 [root@Postgres201 oracle_fdw-2.0.0]# source /home/postgres/.bashrc [root@Postgres201 oracle_fdw-2.0.0]# pg_config [root@Postgres201 oracle_fdw-2.0.0]# make [root@Postgres201 oracle_fdw-2.0.0]# make install FAQ:執行make若出現“/usr/bin/ld: cannot find -lclntsh”;原因是找不到庫liblclntsh文件; 解決方案: 1. 檢查環境變數,看ORACLE有關的環境變數是否設置正確 2. 是否文件名字後有oracle版本信息;需要改名字 該文件在oracle安裝目錄下;本例是需要改名字即可 [root@Postgres201 oracle]# ln -sv libclntsh.so.11.1 libclntsh.so [root@Postgres201 oracle_fdw-2.0.0]# make [root@Postgres201 oracle_fdw-2.0.0]# make install 3、創建外部擴展 adsas=# create extension oracle_fdw; ERROR: could not load library "/app/pg12/lib/postgresql/oracle_fdw.so": libclntsh.so.11.1: cannot open shared object file: No such file or directory 解決方案: 1、創建文件/etc/ld.so.conf.d/oracle.conf 2、添加內容;libclntsh.so.11.1文件所在的路徑 /app/oracle 3、執行載入ldconfig 4、再登錄psql執行 adsas=# create extension oracle_fdw; CREATE EXTENSION
三、創建外部表
CREATE FOREIGN TABLE fdw_game_pay_log ( ID int8 OPTIONS(key 'true'), PAY_TIME timestamp NOT NULL, APPID int2 NOT NULL, QN varchar(20) NOT NULL, ACCOUNTID varchar(64) NOT NULL, AMOUNT decimal(6,2), ORDER_NO text NOT NULL, CP_ORDER_NO text ) server oradb OPTIONS (schema 'ADSAS', table 'TBL_GAME_PAY_LOG');
註意的是:
- 其中schemaname,tablename;需要大寫
- 需要指定在postgres9.3版本以後oracle_fdw支持對外部表的 Insert ,delete ,update ;增加表操作項 options(key 'true') (當值設置為 true|on|yes 表示不可以做增刪改操作)
四、限制
1、不支持直接 insert ... select
adsas=> insert into fdw_game_pay_log select * from tbl_game_pay_log; ERROR: error executing query: OCIStmtExecute failed to execute remote query DETAIL: ORA-08177: can't serialize access for this transaction
解決方法:將語句添加到事務中
adsas=> begin; BEGIN adsas=> insert into fdw_game_pay_log select * from tbl_game_pay_log; INSERT 0 1 adsas=> end; COMMIT
CREATE OR REPLACE PROCEDURE "easou"."P_SYNC_TABLE_DATA" () AS $BODY$ /*********************************************************** 將表tbl_game_pay_log增量複製到fdw_game_pay_log; 達到PG-Oracle數據增量同步 ***********************************************************/ DECLARE vn_old_id int8; vn_new_id int8; BEGIN BGEIN -- 獲取上次提取的id SELECT lid INTO vn_old_id FROM easou.tbl_sync_record WHERE tbl_name = 'tbl_game_pay_log'; -- 截取本次提取的最大id SELECT COALESCE(max(id), 0) INTO vn_new_id FROM easou.tbl_game_pay_log; -- 將本次提取的記錄插入外部表 INSERT INTO easou.fdw_game_pay_log (id, PAY_TIME, APPID, QN, ACCOUNTID, AMOUNT, ORDER_NO, CP_ORDER_NO) SELECT id, PAY_TIME, APPID, QN, ACCOUNTID, AMOUNT, ORDER_NO, CP_ORDER_NO FROM easou.tbl_game_pay_log WHERE id > vn_old_id; -- 更新本次提取的id UPDATE easou.tbl_sync_record SET lid = vn_new_id WHERE tbl_name = 'tbl_game_pay_log'; END; EXCEPTION WHEN OTHERS THEN INSERT INTO tbl_error_log (error_time, error_desc, proc_name, deal_status) VALUES (now()::timestamp, SQLERRM, 'P_SYNC_TABLE_DATA', 0); END; $BODY$ LANGUAGE plpgsql