從Oracle到MariaDB的同步復制
幾種從Oracle數據庫或其它如文本文件、MariaDB (or MySQL for that matter)獲取數據的方法。Oracle數據庫可不愿意你這樣做,因此需要做一些必要的調整。其中一種方式就是使用觸發器,UDF, UPD-communication 和簡單的服務器,這是 從Oracle到MariaDB的同步復制方式系列文章***部分。也就是說從Oracle導出數據到文本文件是Oracle所不愿意看到的。它希望你把數據保存在它里面,圍繞它開展工作,現在你可以使用Oracle dump工具。這已經很好了且能正常處理大多數Oracle的數據類型。
對于復制,如果不使用觸發器或其它機制,那么使用開源的東西可能是比較好的了,或者可以不使用說明特殊工具來做嗎?一種方式是在Oracle的前面放一個代理。這非常有用,但是需要花費太多時間來開發并且要熟悉Oracle的通訊協議,可我不愿意這樣做(我承認我很懶)。
因此現在我只能嘗試其他方式來直接從Oracle復制數據。在后面我將演示一個實際的例子來做此事,不需要太多代碼,但現在我先解釋它是如何工作的。更為困難是如果正確的得到Oracle中的數據,所以這一系列博客的***部分將更多的對Oracle進行相關說明,這是一個好理由(比如:得到可用的而不必自己實現) ,讓我們開始吧。
現在開始,Oracle中沒有 二進制日志(binlog) (也沒有修改日志)。Oracle有重做日志 ,InnoDB/XtraDB 也是使用的這種方式,它們都是基于同樣的目的 —在崩潰發生時能恢復數據庫。 由于重做日志要達成此目的,因此它記錄了比binlog更低層次日志。數據庫中任何修改事件都能夠從Oracle的重做日志中找到,包括很多Oracle的內部處理。Oracle在后臺做了很多東西,與MariaDB強烈依賴操作系統不同它會會更多使用自己的內部管理,比如文件空間管理等類似的東西。 當然這并不是說在這一方面Oracle比MariaDB更好,或與此相反,Oracle誕生的年代你不得不支持多種不同的操作系統,因此在在某些方面就需要設計得透明的(即設計得更抽象,高層次不必依賴操作系統實現)。同時Oracle誕生的年代多數磁盤大小僅為5MB,因此很多都是一些保守做法 (這暴露了我的年齡,是的,我的出生日期早于Mille Small主打歌曲 "My Boy Lollipop"。 與流行的看法相反,它不是Rod Stewart使用口琴獨奏的那首。 ,結束了今天的“無用的知識”課).
在我們進入詳細查看Oracle重做日志之前,我想先解釋一些東西。在Oracle中還有另外一個文件,它很小但是卻很重要,叫著控制文件。控制文件用于跟蹤記錄其它所有文件和關聯的數據庫設置。對于重做日志,有兩個用途。一個基礎方式是 非歸檔(NOARCHIVELOG)模式,意味著日志文件會被重用。這和InnoDB/XtraDB的日志文件使用方式相似,它目的也是提供一種手段來進行崩潰后恢復。想象一下,需要使用這些日志文件進行某一個時間點的恢復,前提是你保存了這些文件,比如:進行了物理備份且保存了這些文件。對于MariaDB,我們會使用binlog進行時間點的恢復。
使用重做日志的目的就是可以對Oracle進行時間點的恢復,我們不得不保存重做日志,在歸檔模式下Oracle有一個單獨的進程"archive"來做,也就是當日志寫滿切換日志時把日志保存在其它地方。所有這一切,當前的和歸檔的重置日志文件都被記錄在Oracle的控制文件中。
這些Oracle知識對于理解代碼如何工作是非常重要的。還有一個我需要簡要的討論一下,就是Oracle的ROWID。ROWID 是Oracle中表的數據行的唯一標識。ROWID實際上是一個物理地址。在某些情況下,當表屬于聚集表時相同的ROWID可用于兩個不同的表,但是對一個表來說,里面的ROWID是唯一標識了一行。 使用表的ROWID,可以使用偽列ROWID,它可以用在WHERE和SELECT語句中。
因此,現在我們要靈活運用上面這些知識。Oracle的重做日志包含了數據庫的變化,因此我們可以使用重做日志來達成MariaDB中binlog相同的目的,如:復制。為了做復制,我們首先需要能夠讀取重做日志,我們可以讀取重做日志文件,但卻相當復雜,如果你堅持這樣做,你可以閱讀 這個文檔 中的例子,但我認為這不是一個好主意。相反,我們應該使用Oracle的工具。對于我們感興趣的DML,我們需要復制處理表的INSERT, UPDATE和DELETE語句,然后在在事務的結束處提交。對于這些操作,我們希望重做日志中包含如下這些數據:
- 操作類型
- 表的唯一標識 (不是表名)
- 列和值的變化
- 行的ROWID
- SCN (系統變更號).
現在我需要說一說SCN。SCN非常簡單;它是一個48位整型數標記了一個事務,每開始一個新事務它就向上增加。你可以獲取表中***更改的SCN,實際上是row所在塊的SCN(你可以跟蹤ROW的變化。有很多奇奇怪怪的選項來滿足用戶的需求。)。
在我寫完這篇博文之前,我想演示下怎么從重做日志文件獲取數據的代碼。在你詢問之前,oracle沒有重做日志單元,或類似這樣的工具。這不是MariaDB,這是Oracle數據庫。Oracle數據庫的工具本身幾乎不是工具,而是 Oracle PL/SQL包。在此例子中是日志分析,或者是一個類似DBMS_LOGMNR包。想要日志分析工作,我們需要在歸檔模式下運行數據庫。所以如果你新安裝了Oracle數據庫,請以特權用戶進行登錄:
- $ sqlplus / as sysdba
然后運行以下命令:
- SQL> SHUTDOWN IMMEDIATE;
- SQL> STARTUP MOUNT;
- SQL> ALTER DATABASE ARCHIVELOG;
- SQL> ALTER DATABASE OPEN;
此外,為了從日志分析中獲得所有數據,我們必須在重做日志中加入"supplemental data"。這意味著我還沒有看其中的數據,但是如果你想看數據請相信我。在同個 SQL*Plus窗口,運行:
- SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
我們可以在此開始分析日志。這包含兩個步驟:***,開始分析日志本身,然后選擇一張表存儲分析日志。讓我們看下怎樣用SQL腳本開始分析日志。調用腳本startlog.sql:
- column min_scn new_value startscn
- column current_scn new_value endscn
- SELECT MIN(FIRST_CHANGE#) min_scn FROM v$log;
- SELECT current_scn FROM v$database;
- EXECUTE DBMS_LOGMNR.START_LOGMNR(STARTSCN => &startscn, -
- ENDSCN => &endscn, -
- OPTIONS => DBMS_LOGMNR.COMMITTED_DATA_ONLY + -
- DBMS_LOGMNR.CONTINUOUS_MINE + -
- DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);
- SET ARRAYSIZE 1
然后運行腳本,因為腳本里不含明顯的退出語句,所以腳本執行后還是會看到SQL*Plus的命令提示符。這和 MariaDB命令行工作方式是不同的。
- $ sqlplus / as sysdba @startlog.sql
現在我們可以獲取一下日志數據,比方說我們有張表稱為T1,并且已經在T1上做了些改動,那我們可以用如下語句獲取相關記錄:
- SQL> SELECT sql_redo FROM v$logmnr_contents WHERE table_name = 'T1' AND seg_owner = 'ANDERS' AND operation IN ('INSERT', 'UPDATE', 'DELETE');
- SQL_REDO
- --------------------------------------------------------------------------------
- insert into "ANDERS"."T1"("C1","C2") values ('1','2');
- insert into "ANDERS"."T1"("C1","C2") values ('2','2');
- update "ANDERS"."T1" set "C2" = '3' where "C2" = '2' and ROWID = 'AAAE5KAAEAAAAFfAAA';
- update "ANDERS"."T1" set "C2" = '3' where "C2" = '2' and ROWID = 'AAAE5KAAEAAAAFfAAB';
這似乎不完整!但里面的有些內容可能是有意義的,對么?有關此系列的下篇博文我們會進行嘗試。這篇博文或多或少都是關于Oracle數據庫的,在下篇博文中將更多描述有關復制到MariaDB的內容,MariaDB也是我們想讓數據存儲的地方,不是么?
快樂的SQL編程吧!