從Oracle遷移到MySQL的各種坑及自救方案
當企業內部使用的數據庫種類繁雜時,或者有需求更換數據庫種類時,都可能會做很多數據遷移的工作。有些遷移很簡單,有些遷移可能就會很復雜,大家有沒有考慮過為了順利完成復雜的數據庫遷移任務,都需要考慮並解決哪些問題呢?
在以前的工作中,我遷移過Oracle到Informix、Oracle和SQLServer、Oracle到MySQL。 在目前的公司又因為去O的關系,做了大量的遷移工作,栽了不少坑,所以和大家交流一下在遷移的過程中的一些實踐。
分享大綱:
-
去O前的準備與考慮
-
確定目標數據庫
-
表和數據對象的遷移及工具比較
-
其它對象的遷移
-
一些性能參數
一、去O前的準備與考慮
因為成本預算等多方面原因,公司決定要去O,在去O之前首先要決定拿什麽來替代Oracle,拿什麽工具將源數據庫的數據導到目標數據庫、怎麽導等的。導的過程的增量數據怎麽處理。導的時候源數據和目標,以及數據的數據類型差異如何處理,像視圖、存儲過程、觸發器這種數據庫對象之間的不同怎麽解決,導的時候如何不影響源數據庫性能。導完以後的數據比對以及數據無誤後應用的性能問題都是要考慮的。
二、確定目標數據庫
在我們做數據遷移之前先確認的就是target database ,就是要遷到什麽數據庫上,經過了一些調研,從速度、流行度等多個方面選擇最終了MySQL。因為相信被Oracle收購後表現會越來越好。
當然也想過使用PosgreSQL,不過做了一個測試,發現MySQL5.7的QPS在比同樣配置的PG要高,基於在線事務對性能的要求,最終還是選擇了MySQL。選擇了MySQL以後,對於MySQL的分支和版本的選擇也很頭痛。Percona增加了很多性能相關補丁,MariaDB支持更多的引擎,官方的版本也能滿足目前的需求,從保守的原則上,我們的核心數據庫最終還是使用了官方的版本,一些不是太核心的數據庫,其它的分支也有在用。
因為MyCat的支持關系最終選擇的是5.6的版本(目前MyCat1.6對MySQL5.7的支持不是太好),為了達到像Oracle的DG/OGG一樣穩定的架構,我們把MySQL的架構做成了雙機房的MHA,並且用了MyCat做了讀寫分離。同樣的Oracle這邊因為同時還有應用在跑,為了分散Oracle的壓力,所有的同步作業也是在備庫和異機房的OGG端進行的操作。
三、表和數據對象的遷移及工具對比
在選擇了合適的DB來替換Oracle後,下一步就是選擇一個合適的遷移工具來做遷移。我們在遷移工具的選擇方面花費了大量時間和精力。遷移是一個漫長而困難的工作,我們在遷移的過程中也歷經了不同的階段,使用了不同的方法。從最初級的load csv升級成自已寫的程序,再去找Oracle和MySQL官方推薦的工具,最後也嘗試了一些 ETL的工具,被這麽多工具摧殘之後,幸運的是能夠在不同的場情下使用不同的方式。
接下來我們對每一種都進行一個簡單的介紹和使用中遇到的一些問題。
1、SQL LOAD
我們在最早的時候只是進行某個項目的遷移工作,因為時間的關系並沒有進行遷移工具的選型以及使用,使用了最簡單的方式就是SQL LOAD。
所有的操作步驟比把大象放進冰箱還要簡單,簡單得只要分兩步,第一步把Oracle的數據導成CSV或者SQL,然後再load或者source到MySQL中就可以了。
把Oracle的數據導成CSV或者SQL可以用很多工具,比如SQL developer或者toad,不過我還是更推薦spool,大家應該都用過spool,他可以結合set把內容輸出到指定的文件中,然後選擇合理的行列分隔符,就可以產生csv文件了。
使用SQL LOAD的優點就是速度快和超級簡單,不過同樣的,它也會有很多弊端,它很難做成自動化和全面普及到很多張表上,每有一張表的操作就要寫SQL拼CSV,然後還不能保證是一樣的分隔符,大多數時候對lob字段操作也很麻煩。對類似於comments的評論字段也很難原樣的copy過去。
我們來看一個簡單的例子:
第一步我先在Oracle這邊創建了一張表,很簡單只有四列,然後insert了三條數據查看了一下內容。
做了一些簡單的可能會用到的查詢。
看一下導出用的spool的內容,實際用的時候肯定會比這個更復雜,要對換行、time、lob等進行更多的函數處理。然後把數據導了出來看一下。
接著我又在MySQL創建一張一樣的表把數據load了進去。load的語法不是我們今天要分享的重點,它的作用就是把file load into table.可以指定行列分隔符。 可以看到數據load進去了三行,同時也給出了三個警告,第二行一個,第三行兩個,分別是int類型的列傳了一個空字符串和時間類型的被截取了。查看一下表裏的數據,發現和預期的不一樣。
然後把剛剛在Oracle那邊進行的查詢再次查詢一下,發現結果都變得不一樣了。
這是因為在MySQL裏int類型如果插入的為空,結果會自動轉成0。
官方文檔上有明確的說明:
An empty field value is interpreted different from a missing field:
For string types, the column is set to the empty string.
For numeric types, the column is set to 0.
For date and time types, the column is set to the appropriate “zero” value for the type.
我們再看一下用etl工具遷移過來的數據,可以發現數據被insert成了null ,符合了Oracle的意思,其實這就是sqlload時一些弊端,數據類型可能弄得不是原來的數據了。同樣的,我們也可以設置成嚴格的模式,int類型的不允許插入null,我們會在下面的sql_mode裏講到。
2、Python
遷了部分數據之後覺得load數據雖然簡單和快,但是瑜不掩瑕,總是有這樣那樣的問題,遷移之後往往還會同時伴隨著大量的數據修復工作。
很快的,我們就棄用了這種操作,在這裏要說明一下SQL LOAD的操作因為速度又快又不依賴其它組件,所以適用於數據類型並不復雜的單表操作,然後就寫了python代碼來接替它來完成數據遷移的操作,使用python的話其實也很簡單,可以分為三步,第一步就是建立配置表,同時和MySQL的表進行mapping,標識出是全量的還是增量的,如果是增量的,以什麽做為增量來處理。第二步就是根據mapping進行code、code、code,最後根據不同的入參寫好crontab就可以進行調度就可以了。
使用python處理的過程中可以對一些數據進行轉換,也更加靈活地配置了一些選項,實現了較強的邏輯控制,當然也有一些缺點:它的速度慢了太多(不過也只比load慢,比起來後面要介紹的Java編寫的軟件還是快很多)。對於異常的處理也花費了大量的代碼邏輯,同時也要會寫代碼。
我們可以簡單來看一下它的實現:
這一個代碼片斷,顯示了增量同步每一天的數據邏輯。
這是每天跑批之後生成的log,可以看出來把warning和error都列了出來,同時也對行數進行了統計。已經可以說是一個不錯的小型產品了。可看出來6w條數據用了4s和load來比算是慢的,但是和Java之類的比算是快的了。
3、OGG
因為python開發的這一套東西雖然也不算太慢,但因為要自己用代碼實現較強的邏輯,並且有些需求在Oracle的業務還沒有完全下線之前要實時地同步到MySQL裏來,所以我們又研究了一下OGG的做法。先提前說一下,OGG的應用場景就是那種要求實時並且可能需要回寫數據的。
OGG的用法說起來很簡單,只要配置好Oracle端,配置好MySQL端,然後對應的進程起起來就可以了。但用過OGG的人都知道配置一套OGG本身就很麻煩了,異構數據庫之間再進行同步的話,調通並可用需要很久的配置時間,所以我大致說一下做法,除非真的有這種硬性需求,不然不推薦使用。
簡單說一下用OGG的過程和註意事項:
1、 5.6版本需要12.1.2版本的OGG才支持
2、異構數據庫之間不支持DDL復制
-
從Oracle同步到MySQL,屬於異構架構,不支持DDL同步,包括添加和刪除字段,添加和刪除索引,重命名表,表分析統計數據。
-
若是涉及到源端和目標端DDL操作,需要進行源端和目標端同時手工操作。
3、必須要配置defgen,且文件必須放在相同的目錄。
4、如果要是雙向的話,就必須把MySQL端的binglog設置成row
binlog_format: This parameter sets the format of the logs. It must be set to the value of ROW, which directs the database to log DML statements in binary format. Any other log format (MIXED or STATEMENT) causes Extract to abend.
5、GoldenGate對MySQL只支持InnoDB引擎。所以,在創建MySQL端的表的時候,要指定表為InnoDB引擎。
create table MySQL (name char(10)) engine=innodb;
所有的幫助可以online help裏去看
http://docs.Oracle.com/goldengate/c1221/gg-winux/GIMYS/system_requirements.htm#GIMYS122
4、MySQL Migration Toolkit
OGG是Oracle官方推薦的工具,使用原理就是基於日誌的結構化數據復制,通過解析源數據庫在線日誌或歸檔日誌獲得數據的增量變化,再將這些變化應用到目標數據庫,那MySQL官方沒有提供工具呢?答應是肯定的。
MySQL官方同樣也提供一個用於異構之間的數據遷移工具,從MySQL到其它數據庫,或者從其它數據庫到MySQL都是可以的。這個工具就是MySQL Migration Toolkit。這個工具可以單獨被下載,也被集成到了MySQL wrokbench裏。不過如果單獨下載的話 只有windows的版本。
https://downloads.MySQL.com/archives/migration/
這是一個基於Java的程序,所以依賴於jar包,使用它的第一步就是load一個odbc.jar。接著就可以把源端和目標端進行配置連接,選擇要導入的對象(可以包含視圖,但是一般有子查詢的會報錯),進行導入就可以了。
使用它的優點就是可以在MySQL端自動創建表,但有可能自動convert的類型若有問題,需要人為參與一下進行處理,比如Oracle中通常會對Timestamp類型的數據設置默認值sysdate,但在MySQL中是不能識別的。
缺點就是只有windows的平臺有,在導大數據量時,極有可能就hang住了。所以個人感覺它的適用場景就是一次性導入的小批量的數據。
5、KETTLE
上面提到的幾種工具都是一步一個坑使用過之後發現並沒有盡善盡美,總有這樣或者那樣的不足,接下來我們來推薦的就是終級必殺的好用的etl工具:KETTLE。
它是一款純Java編寫的軟件,就像它的名字(水壺)一樣,是用來把各種數據放到一個壺裏,然後以一種指定的格式流出。當然你也可以使用DS(datastage)或者Informatica。不過這兩個是收費的,而kettle是免費開源的。
這裏只介紹它最簡單的能滿足我們把數據從Oracle遷移到MySQL的功能。
同理,第一步把jar包load進去,不同的是,這次要load的是MySQL的jar包。需要註意的是,如果你的MySQL版本不同可能需要load不同的jar包。第二步同也是配置連接信息,保證你的源和目標都連接成功,最後一步就是簡單的拖拖拽拽。最後run一下就可以了。
它的優點就是配置起來比OGG快,但是同樣可以通過job做到實時同步,處理速度和Python旗鼓相當,卻不用自己來寫mapping關系,並且提供了圖形化界面。也能和Migration Toolkit一樣同時創建表(新增一個Java腳本),進行類型轉換,但日誌更詳細。只是可能學習成本高一點,要看的懂一些Java報錯方便調試。
接下來我們簡單看一個demo:
我們運行spoon.sh之後可以打開這個界面。view一界顯示了這個轉換的名字、數據源、處理步驟等,中間區域是你拖拽出來的操作,一個輸入,一個輸出。這就是一個簡單的數據遷移的所有步驟。
打開input的內容,就是很簡單的一條SQL在哪個源數據庫上抽取數據,當然這條SQL也可以是拖拽生成出來,類似於congos的拖拽生成報表。千萬要註意的是,不要加分號!
output的內容就顯示豐富了很多,選擇目標數據源,以及會自動的mapping列的信息,還有在遷移之間要不要先清空,遷移過程中如果遇到問題了會不會中止。
這裏就是顯示了它超越Migration tools的log最細粒度到行級別,可以更快地分析出問題。
這裏則是詳細的日誌輸出。一般如果定時跑批處理的話,把它重定向到具體的log裏,然後當做發送郵件。
四、其它對象的遷移
上面用了很長的篇幅介紹了一下幾種遷移的工具,每種遷移的方式都是各有千秋,在合適的場景下選擇適合自己的方法進行操作。不過剛剛遷移的都是表和數據對象。我們都知道在數據庫還有一些其它的對象,像視圖、物化視圖、存儲過程、函數、包,或者一個索引,同樣的SQL是不是也需要改寫,都是我們需要考慮到的一個因素。
接下來我們來看一下其它對象怎麽遷移。
1、view
在MySQL裏view是不可以嵌套子查詢的:
create view v_test as select * from (select * from test) t;
ERROR 1349 (HY000): View‘s SELECT contains a subquery in the FROM clause
解決方法就是view的嵌套:
create view v_sub_test as select * from test;
Query OK, 0 rows affected (0.02 sec)
create view v_test as select * from v_sub_test;
Query OK, 0 rows affected (0.00 sec)
2、物化視圖
物化視圖用於預先計算並保存表連接或聚集等耗時較多的操作結果,這樣在執行查詢時,就可以避免進行這些耗時的操作,而從快速得到結果。但是MySQL裏沒有這個功能。通過事件調度和存儲過程模擬物化視圖,實現的難點在於更新物化視圖,如果要求實時性高的更新,並且表太大的話,可能會有一些性能問題。
3、Trigger、存儲過程、package
1)Oracle創建觸發器時允許or,但是MySQL不允許。所以遷移時如果有需要寫兩個。
2)兩種數據庫定義變量的位置不同,而且MySQL裏不支持%type。這個在Oracle中用得太頻繁了,是個好習慣。
3)elseif的邏輯分支語法不同,並且MySQL裏也沒有for循環。
4)在MySQL中不可以返回cursor,並且聲明時就要賦對象。
5)Oracle用包來把存儲過程分門別類,而且在package裏可以定義公共的變量/類型,既方便了編程,又減少了服務器的編譯開銷。可MySQL裏根本沒有這個概念。所以MySQL的函數也不可以重載。
6)預定義函數。MySQL裏沒有to_char() to_date()之類的函數,也並不是所有的Oracle都是好的,就像substring()和load_file()這樣的函數,MySQL有,Oracle卻沒有。
7)MySQL裏可以使用set和=號給變量賦值,但不可以使用:=。 而且在MySQL裏沒 || 來拼接字符串。
8)MySQL的註釋必須要求-- 和內容之間有一個空格。
9)MySQL存儲過程中只能使用leave退出當前存儲過程,不可以使用return。
10)MySQL異常對象不同,MySQL同樣的可以定義和處理異常,但對象名字不一樣。
4?分頁語句
MySQL中使用的是limit關鍵字,但在Oracle中使用的是rownum關鍵字。所以每有的和分頁相關的語句都要進行調整。
5?JOIN
如果你的SQL裏有大量的(+),這絕對是一個很頭疼的問題。需要改寫。
6?group by語句
Oracle裏在查詢字段出現的列一定要出現在group by後面,而MySQL裏卻不用。只是這樣出來的結果可能並不是預期的結果。造成MySQL這種奇怪的特性的歸因於sql_mode的設置,一會會詳細說一下sql_mode。不過從Oracle遷移到MySQL的過程中,group by語句不會有跑不通的情況,反過來遷移可能就需要很長的時間來調整了。
7?bitmap位圖索引
在Oracle裏可以利用bitmap來實現布隆過濾,進行一些查詢的優化,同時這一特性也為Oracle一些數據倉庫相關的操作提供了很好的支持,但在MySQL裏沒有這種索引,所以以前在Oracle裏利於bitmap進行優化的SQL可能在MySQL會有很大的性能問題。
目前也沒有什麽較好的解決方案,可以嘗試著建btree的索引看是否能解決問題。要求MySQL提供bitmap索引在MySQL的bug庫裏被人當作一個中級的問題提交了上去,不過至今還是沒有解決。
8?分區表(Partitioned table)
需要特殊處理,與Oracle的做法不同,MySQL會將分區鍵視作主鍵和唯一鍵的一部分。為確保不對應用邏輯和查詢產生影響,必須用恰當的分區鍵重新定義目標架構。
9?角色
MySQL8.0以前也沒有role的對象。在遷移過程中如果遇到的角色則是需要拼SQL來重新賦權。不過MySQL更好的一點是MySQL的用戶與主機有關。
10?表情和特殊字符
在Oracle裏我們一般都選擇AL32UTF8的字符集,已經可以支付生僻字和emoji的表情了,因為在遷移的時候有的表包含了大量的表情字符,在MySQL裏設置了為utf8卻不行,導過去之後所有的都是問號,後來改成了utf8mb4才解決問題,所以推薦默認就把所有的DB都裝成utf8mb4吧。
Oracle和MySQL差異遠遠不止這些,像閃回、AWR這些有很多,這裏只談一些和遷移工作相關的。
五、數據校驗
當數據遷移完成後,如何確保數據的正確遷移、沒有遺漏和錯誤是一個很難的問題。這裏的難不是實現起來困難,而是要把它自動化,達到節省人力的目標有點難,因為兩者的數據類型不同,數據量偏大,寫一些腳本去做檢查效果不大。
我們的數據校檢工作主要分為在導入過程中的log和警告,在load的時候SHOW WARNINGS和errors,在使用Python、OGG、Kettle等工具時詳細去看每個errors信息。
1、count(*)
遷移或增量操作完成以後,用最簡單的count(*)去檢查,在MySQL和Oracle上檢查進行比對。如果數據量一致,再進行數據內容的驗證。由於數據量太大,只進行了抽樣檢測。人工的手動檢驗如果沒有問題了,可以使用應用程序對生產數據庫的副本進行測試,在備庫上進行應用程序的測試,從而進行再一次的驗檢。
2、etl工具
另外推薦的一種方式就是使用etl工具配置好MySQL和Oracle的數據源,分別對數據進行抽取,然後生成cube,進行多緯度的報表展現。數據是否有偏差,可以一目了然看清。
數據的完整性驗證是十分重要的,千萬不要怕驗證到錯誤後要花好長時候去抽取同步的操作這一步。因為一旦沒有驗證到錯誤,讓數據進行了使用卻亂掉了,後果將更嚴重。
3、SQL_MODE
https://dev.MySQL.com/doc/refman/5.5/en/sql-mode.html
MySQL服務器能夠工作在不同的SQL模式下,針對不同的客戶端,以不同的方式應用這些模式。這樣應用程序就能對服務器操作進行量身定制,以滿足自己的需求。這類模式定義了MySQL應支持的SQL語法,以及應該在數據上執行何種確認檢查。
-
TRADITIONAL
設置“嚴格模式”,限制可接受的數據庫輸入數據值(類似於其它數據庫服務器),該模式的簡單描述是當在列中插入不正確的值時“給出錯誤而不是警告”。
-
ONLY_FULL_GROUP_BY
在MySQL的sql_mode=default的情況下是非ONLY_FULL_GROUP_BY語義,也就是說一條select語句,MySQL允許target list中輸出的表達式是除聚集函數、group by column以外的表達式,這個表達式的值可能在經過group by操作後變成undefined,無法確定(實際上MySQL的表現是分組內第一行對應列的值)
select list中的所有列的值都是明確語義。
簡單來說,在ONLY_FULL_GROUP_BY模式下,target list中的值要麽是來自於聚集函數的結果,要麽是來自於group by list中的表達式的值。
Without Regard to any trailing spaces
All MySQL collations are of type PADSPACE. This means that all CHAR, VARCHAR, and TEXT values in MySQL are compared without regard to any trailing spaces. “Comparison” in this context does not include the LIKE pattern-matching operator, for which trailing spaces are significant.
MySQL校對規則屬於PADSPACE,MySQL對CHAR和VARCHAR值進行比較都忽略尾部空格,和服務器配置以及MySQL版本都沒關系。
-
explicit_defauls_for_timestamp
MySQL中TIMESTAMP類型和其它的類型有點不一樣(在沒有設置explicit_defaults_for_timestamp=1的情況下),在默認情況下,如果TIMESTAMP列沒有顯式的指明null屬性,那麽該列會被自動加上not null屬性(而其他類型的列如果沒有被顯式的指定not null,那麽是允許null值的),如果往這個列中插入null值,會自動設置該列的值為current timestamp值,表中的第一個TIMESTAMP列,如果沒有指定null屬性或者沒有指定默認值,也沒有指定ON UPDATE語句,那麽該列會自動被加上DEFAULT 。
CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP屬性。第一個TIMESTAMP列之後的其它的TIMESTAMP類型的列,如果沒有指定null屬性,也沒有指定默認值,那該列會被自動加上DEFAULT ‘0000-00-00 00:00:00‘屬性。如果insert語句中沒有為該列指定值,那麽該列中插入‘0000-00-00 00:00:00‘,並且沒有warning。
如果我們啟動時在配置文件中指定了explicit_defaults_for_timestamp=1,MySQL會按照如下的方式處理TIMESTAMP列。
此時如果TIMESTAMP列沒有顯式的指定not null屬性,那麽默認的該列可以為null,此時向該列中插入null值時,會直接記錄null,而不是current timestamp。並且不會自動的為表中的第一個TIMESTAMP列加上DEFAULT CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP屬性,除非你在建表時顯式的指明。
六、一些性能參數
我們可以在導入數據的時候預先的修改一些參數,來獲取最大性能的處理,比如可以把自適應hash關掉,Doublewrite關掉,然後調整緩存區,log文件的大小,把能變大的都變大,把能關的都關掉來獲取最大的性能,我們接下來說幾個常用的:
-
innodb_flush_log_at_trx_commit
如果innodb_flush_log_at_trx_commit設置為0,log buffer將每秒一次地寫入log file中,並且log file的flush(刷到磁盤)操作同時進行。該模式下,在事務提交時,不會主動觸發寫入磁盤的操作。
如果innodb_flush_log_at_trx_commit設置為1,每次事務提交時MySQL都會把log buffer的數據寫入log file,並且flush(刷到磁盤)中去。
如果innodb_flush_log_at_trx_commit設置為2,每次事務提交時MySQL都會把log buffer的數據寫入log file。但是flush(刷到磁盤)的操作並不會同時進行。該模式下,MySQL會每秒執行一次 flush(刷到磁盤)操作。
註意:由於進程調度策略問題,這個“每秒執行一次 flush(刷到磁盤)操作”並不是保證100%的“每秒”。
-
sync_binlog
sync_binlog 的默認值是0,像操作系統刷其它文件的機制一樣,MySQL不會同步到磁盤中去,而是依賴操作系統來刷新binary log。
當sync_binlog =N (N>0) ,MySQL 在每寫N次 二進制日誌binary log時,會使用fdatasync()函數將它的寫二進制日誌binary log同步到磁盤中去。
註:如果啟用了autocommit,那麽每一個語句statement就會有一次寫操作;否則每個事務對應一個寫操作。
-
max_allowed_packet
在導大容量數據特別是CLOB數據時,可能會出現異常:“Packets larger than max_allowed_packet are not allowed”。這是由於MySQL數據庫有一個系統參數max_allowed_packet,其默認值為1048576(1M),可以通過如下語句在數據庫中查詢其值:show VARIABLES like ‘%max_allowed_packet%‘;
修改此參數的方法是在MySQL文件夾找到my.cnf文件,在my.cnf文件[MySQLd]中添加一行:max_allowed_packet=16777216
-
innodb_log_file_size
InnoDB日誌文件太大,會影響MySQL崩潰恢復的時間,太小會增加IO負擔,所以我們要調整合適的日誌大小。在數據導入時先把這個值調大一點。避免無謂的buffer pool的flush操作。但也不能把 innodb_log_file_size開得太大,會明顯增加 InnoDB的log寫入操作,而且會造成操作系統需要更多的Disk Cache開銷。
-
innodb_log_buffer_size
InnoDB用於將日誌文件寫入磁盤時的緩沖區大小字節數。為了實現較高寫入吞吐率,可增大該參數的默認值。一個大的log buffer讓一個大的事務運行,不需要在事務提交前寫日誌到磁盤,因此,如果你有事務比如update、insert或者delete 很多的記錄,讓log buffer 足夠大來節約磁盤I/O。
-
innodb_buffer_pool_size
這個參數主要緩存InnoDB表的索引、數據、插入數據時的緩沖。為InnoDN加速優化首要參數。一般讓它等於你所有的innodb_log_buffer_size的大小就可以,
innodb_log_file_size要越大越好。
-
innodb_buffer_pool_instances
InnoDB緩沖池拆分成的區域數量。對於數GB規模緩沖池的系統,通過減少不同線程讀寫緩沖頁面的爭用,將緩沖池拆分為不同實例有助於改善並發性。
總結
-
一定要選擇合適你的遷移工具,沒有哪一個工具是最好的。
-
數據的檢驗非常重要,有的時候我們遷過去很開心,校驗時發生錯誤,這個時候必須要重來。
-
重復地遷移是很正常的,合乎每次遷移可能需要很長時間,總會是有錯誤的,要做好再遷的心態。轉 http://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&mid=2650760496&idx=1&sn=5d983117b0f5402362d3f6751497b4ac&chksm=f3f9d0a5c48e59b3f4c7e8dda11a4aa1b1e24cb0e9ee30c6c0abdde75a2d546a1b5df3dc3fc7&mpshare=1&scene=23&srcid=0607Yvy0TXxRKJasZ8j1JIUy#rd 作者:馮帥
從Oracle遷移到MySQL的各種坑及自救方案