通過EDB-Mtk工具從Oracle向PostgreSQL遷移數據
一. 參考資料
postgresql-10-US.pdf
Postgres_Plus_Migration_Guide.pdf
www.postgresql.org
www.enterprisedb.com
*由於技術更新很快,請註意本文的時效性。
二. 環境說明
源數據庫:Oracle 12cR2下的一個pdb,服務名aegisdb
目標數據庫:postgresql-10.1
三. 準備遷移工具
工具名稱: EDB Migration Toolkit(EDB MTK)
EDB MTK可以通過PostgreSQL安裝後自帶的Application Stack Builder軟件下載並安裝,也可以單獨下載(目前最新的51.0.1下載地址為http://sbp.enterprisedb.com/getfile.jsp?fileid=10872)。該遷移工具並不是必須,但它可以大大簡化Oracle的數據庫對象向PostgreSQL的轉移過程:
數據庫中的數據可以很方便的從Oracle遷移到PostgreSQL;
Oracle中的存儲過程代碼由於PLSQL和PL/PGSQL差異較大,需要逐個手工修改後遷移。
5.1 安裝
安裝EDB MTK工具的服務器上需預裝好JAVA.
我這裏把EDB MTK和PostgreSQL裝在了同一個服務器上,可以不需要這樣。
# ./migrationtoolkit-51.0.1-1-linux-x64.run --mode text Language Selection Please select the installation language [1] English - English [2] Japanese - 日本語 [3] Simplified Chinese - 簡體中文 [4] Traditional Chinese - 繁體中文 [5] Korean - ??? Please choose an option [1] : ---------------------------------------------------------------------------- Welcome to the Migration Toolkit Setup Wizard. ---------------------------------------------------------------------------- Please read the following License Agreement. You must accept the terms ofthis agreement before continuing with the installation. <<此處省略協議內容>> Do you accept this license? [y/n]: y ---------------------------------------------------------------------------- Please specify the directory where Migration Toolkit will be installed. Installation Directory [/opt/edb/mtk]: /PostgreSQL/edbmtk ---------------------------------------------------------------------------- Setup is now ready to begin installing Migration Toolkit on your computer. Do you want to continue? [Y/n]: Y ---------------------------------------------------------------------------- Please wait while Setup installs Migration Toolkit on your computer. Installing Migration Toolkit 0% ______________ 50% ______________ 100% ######################################### ---------------------------------------------------------------------------- EnterpriseDB is the leading provider of value-added products and services for the Postgres community. Please visit our website at www.enterprisedb.com # chown -R postgres:postgres /PostgreSQL/edbmtk
5.2 配置JDBC庫文件
從https://www.enterprisedb.com/advanced-downloads的跳轉連接下載對應Oracle版本的第三方JDBC驅動ojdbc8.jar。放置於服務器的JAVA_HOME/jre/lib/ext下。
從https://www.enterprisedb.com/advanced-downloads的跳轉鏈接下載對應PostgreSQL版本的JDBC驅動postgresql-42.2.2.jar。放置於服務器JAVA_HOME/jre/lib/ext下。
5.2 配置遷移工具
$ cd /PostgreSQL/edbmtk/etc/ $ vi toolkit.properties SRC_DB_URL=jdbc:oracle:thin:@10.19.100.19:1521/aegisdb SRC_DB_USER=aegisdb SRC_DB_PASSWORD=123456 TARGET_DB_URL=jdbc:postgresql://localhost:5432/aegis TARGET_DB_USER=postgres TARGET_DB_PASSWORD=123456
配置文件中以JDBC的方式配置目標庫(PG)和源庫(Oracle)的連接串,因為這裏Oracle是12c的一個pdb,所以需要使用服務名不能用SID的方式。
四. 遷移
4.1 生成遷移腳本
雖然EDB MTK工具也提供在線直接遷移的功能,但異構數據庫之間的數據庫對象遷移會有非常多的問題,因此建議先用離線遷移模式導出源庫(Oracle)中所有對象的創建腳本,逐一檢查是否符合目標庫(PostgreSQL)的SQL語法,修改完畢後再提交到目標庫執行。
生成遷移腳本:
$ mkdir /PostgreSQL/mtk_scripts $ mkdir /PostgreSQL/mtk_data $ cd /PostgreSQL/edbmtk/bin/ $ ./runMTK.sh -targetdbtype postgres -schemaOnly -offlineMigration /PostgreSQL/mtk_scripts AEGISDB
runMTK腳本的最後一個參數表示要轉移數據的Oracle schema名稱,需要大寫。
完成後,在/PostgreSQL/mtk_scripts/ 目錄下生成Oracle中所有對象對應的PostgreSQL對象的創建腳本。
$ cd /PostgreSQL/mtk_scripts/ $ ls -l total 96 -rw-rw-r-- 1 postgres postgres 2789 May 9 10:47 mtk_aegisdb_constraint_ddl.sql -rw-rw-r-- 1 postgres postgres 41829 May 9 10:48 mtk_aegisdb_ddl.sql -rw-rw-r-- 1 postgres postgres 417 May 9 10:48 mtk_aegisdb_index_ddl.sql -rw-rw-r-- 1 postgres postgres 24 May 9 10:47 mtk_aegisdb_schema_ddl.sql -rw-rw-r-- 1 postgres postgres 2750 May 9 10:47 mtk_aegisdb_sequence_ddl.sql -rw-rw-r-- 1 postgres postgres 32326 May 9 10:47 mtk_aegisdb_table_ddl.sql -rw-rw-r-- 1 postgres postgres 3619 May 9 10:48 mtk_aegisdb_view_ddl.sql
其中mtk_aegisdb_ddl.sql為所有對象腳本(其內容就是其他所有腳本內容的並集)。其他腳本名稱自明,就不做解釋了。
腳本在實際導入PostgreSQL前需要進一步校驗,確保語法正確。
4.2 表
4.2.1 表結構
表結構位於生成的腳本mtk_aegisdb_table_ddl.sql中,生成的腳本裏已經對大部分的數據類型等異構數據庫間不兼容項做了映射,但還需要對導出的建表語句進行手工修改以適用於PostgreSQL。如果條件允許可以先在建好的數據庫裏跑一次這個腳本,檢查日誌中的報錯信息後再做修改:
$ psql -U postgres -d aegis -o ./imp.log -f mtk_aegisdb_table_ddl.sql
可以通過在PG上執行下面的SQL語句來獲得一次性清理所有已經導入的表對象的腳本:
select ‘drop table aegisdb.‘||tablename||‘;‘ from pg_tables where schemaname=‘aegisdb‘
其中需要修改的地方包括但不限於:
數據類型
1. date -> timestamp(0) without time zone
Oracle date類型是yyyy-mm-dd hh:mi:ss
PG date類型是yyyy-mm-dd,因此需要換為timestamp(0) without time zone,0表示秒之後的位數有幾位
2. default sysdate -> default NOW()
PG無sysdate,使用 NOW()函數替代
分區表
PG的分區是以“主表+子表+規則”的方式實現的(如果試用PG10,則不需要自己寫規則),建表語句和Oracle完全不同,EDB MTK無法轉換,需要自行修改。
PG分區表建表語句參考如下:
-- 主表 CREATE TABLE MESSAGE_BK_OLD ( ID NUMERIC(38) NOT NULL, MSGCONTENT TEXT, STATUS NUMERIC(2) NOT NULL, ADDR_TYPE VARCHAR(4) NOT NULL, ADDRESS VARCHAR(60) NOT NULL, PRIORITY VARCHAR(10) NOT NULL, RESEND NUMERIC(10) NOT NULL, TIME timestamp(0) without time zone NOT NULL, RAWID NUMERIC(38) NOT NULL, SENDER_ID NUMERIC(32), SOURCE VARCHAR(50) NOT NULL, MSGTYPE VARCHAR(20) NOT NULL, TAG NUMERIC(2) DEFAULT 0, SOURCEADDR VARCHAR(60), COPYSTATUS NUMERIC(2), FLIGHT_NO VARCHAR(10), ORIGIN_DESTADDR VARCHAR(256), DOUBLESIGNATURE VARCHAR(10) ); --子表1 create table MESSAGE_BK_OLD_P1( check(TIME<TO_timestamp(‘2008-06-01 00:00:00‘, ‘YYYY-MM-DD HH24:MI:SS‘)::timestamp(0) without time zone)) INHERITS (MESSAGE_BK_OLD); --子表2 create table MESSAGE_BK_OLD_P2( check(TIME>=TO_timestamp(‘2008-06-01 00:00:00‘, ‘YYYY-MM-DD HH24:MI:SS‘)::timestamp(0) without time zone)) INHERITS (MESSAGE_BK_OLD); --規則1,這裏其實不需要規則了,因為數據庫是PostgreSQL 10.1 CREATE OR REPLACE RULE MESSAGE_BK_OLD_P1 AS ON INSERT TO MESSAGE_BK_OLD WHERE TIME < TO_timestamp(‘2008-06-01 00:00:00‘, ‘YYYY-MM-DD HH24:MI:SS‘)::timestamp(0) without time zone DO INSTEAD INSERT INTO MESSAGE_BK_OLD_P1 VALUES(NEW.*); --規則2,這裏其實不需要規則了,因為數據庫是PostgreSQL 10.1 CREATE OR REPLACE RULE MESSAGE_BK_OLD_P2 AS ON INSERT TO MESSAGE_BK_OLD WHERE TIME >= TO_timestamp(‘2008-06-01 00:00:00‘, ‘YYYY-MM-DD HH24:MI:SS‘)::timestamp(0) without time zone DO INSTEAD INSERT INTO MESSAGE_BK_OLD_P2 VALUES(NEW.*);
所有建表腳本修改完後,在數據庫上執行,生成表對象:
$ psql -U postgres -d aegis -o ./imp.log -f mtk_typeb_table_ddl.sql
如果還有報錯,則反復進行修改步驟,直至不報錯。
4.2.2 數據
在4.2.1成功轉移所有數據庫表對象的基礎上,數據遷移也可以通過EDB MTK工具進行。
$ ./runMTK.sh -sourcedbtype oracle -targetdbtype postgres -dataOnly -logDir /PostgreSQL/mtk_scripts/ AEGISDB
通過 dataOnly選項指定只做數據轉移,最後一個參數是要轉移的Oracle schema,需要大寫。有1點需要註意:
CLOB兼容性
Oracle的CLOB字段可以含有不在ASCII碼表中的字符,而PG對應CLOB的text類型不支持這種字符。例如,0x00(C裏的‘\0‘)。該問題無法通過數據庫解決,只能通過應用想辦法繞開,常見辦法是吧這類字符替換成其他在ASCII碼表裏的特定字符。
另外,Offline轉移可以把源庫的數據做成可以使用postgres COPY命令導入的文件,但是需要自行編寫導入腳本;
4.3 索引
索引創建語句位於生成的腳本mtk_aegisdb_index_ddl.sql中。索引一定要等待數據導入後再創建,避免外鍵約束導致數據無法導入。
已知的問題點有:
函數索引
PG支持函數索引,但函數名稱和Oracle不同,需要把函數索引使用的函數修改成對應的PG函數。
分區表的分區索引
PG沒有全局/分區索引的概念,由於其分區表實現機制,實際分區表上的所有索引都是局部分區索引。
執行腳本創建索引:
$ psql -U postgres -d aegis -o ./imp.log -f mtk_aegisdb_index_ddl.sql
4.4 約束
約束創建語句位於生成的腳本mtk_aegisdb_constraint_ddl.sql中。腳本可以直接在數據庫中執行,可能會報大量的錯誤,這是由於主鍵約束,唯一約束在上面建表腳本、創建索引腳本中都已經包含了,再次創建會報對象已經存在;而非空約束在PG中不需要單獨創建。
這裏我的約束腳本沒有其他額外的問題,直接執行並忽略錯誤即可:
$ psql -U postgres -d aegis -o ./imp.log -f mtk_aegisdb_constraint_ddl.sql
4.5 視圖
視圖創建語句位於生成的腳本mtk_aegisdb_view_ddl.sql中。PG的視圖不兼容Oracle的偽列,含有Oracle偽列的視圖需要修改創建語句並在使用上做出相應修改;PG9.3以及以前的版本不支持with check option。
我的視圖均為標準語句,直接執行腳本在數據庫中創建視圖:
$ psql -U postgres -d aegis -o ./imp.log -f mtk_aegisdb_view_ddl.sql
4.6 Sequence
Sequence創建語句位於生成的腳本mtk_aegisdb_sequence_ddl.sql中。需要做序列上限值檢查後再在PG裏執行。Oracle的Sequence對象的最大值可以寫成任意的溢出值(如:999999999999999999999999),但PG的Sequence對象最大值上限為9223372036854775807,超過這個值的創建語句會報錯。
$ psql -U postgres -d aegis -o ./imp.log -f mtk_aegisdb_sequence_ddl.sql
4.7 函數、存儲過程和包
使用EDB MTK生成離線遷移腳本時是不會產生代碼的創建腳本的,而且由於PLSQL和PLPGSQL的語法差異較大,在線遷移遷移的代碼對象幾乎肯定會報錯。代碼部分需要逐個手工修改並轉移,這也是整個遷移工作中最耗費時間和人力的部分。
參與數據庫代碼轉移的人員需要有Oracle代碼和PG代碼的編寫能力。
通過EDB-Mtk工具從Oracle向PostgreSQL遷移數據