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