這是堅持技術寫作計划(含翻譯)的第26篇,定個小目標999,每周最少2篇。
最近工作需要,需要從Oracle導數據到Mysql,並且需要進行適當的清洗,轉換。
數據量在5億條左右,硬件環境為Winserver 2008R2 64位 ,64G,48核,1T hdd,kettle是8.2,從Oracle(11G,linux服務器,局域網連接)抽到mysql(5.7,本機,win server)。
優化前的速度是讀1000r/s(Oracle)左右,寫1000r/s左右。
優化后的速度是讀8Wr/s(Oracle)左右,寫4Wr/s左右。
因為表的字段大小和類型以及是否有索引都有關系,所以總體來說,提升了20-50倍左右。
mysql 優化
mysql此處只是為了遷移數據用,實際上用csv,或者clickhouse也行。但是擔心csv在處理日期時可能有問題,而clickhouse不能在win下跑,而條件所限,沒有多余的linux資源,而mysql第三方開源框架(不管是導入hdfs),還是作為clickhouse的外表,還是數據展示(supserset,metabase等),還是遷移到tidb,都很方便。所以最終決定用mysql。
Note:此處的mysql只做臨時數據遷移用,所以可以隨便重啟跟修改mysqld參數。如果是跟業務混用時,需要咨詢dba,確保不會影響其他業務。
mysql 安裝及配置優化
- 從 dev.mysql.com/downloads/m… 下載64位 zip mysql
- 解壓 mysql-5.7.26-winx64.zip 到目錄,比如 D:\mysql-5.7.26-winx64
- 創建D:\mysql-5.7.26-winx64\my.ini
[mysqld]
port=3306
basedir=D:\mysql-5.7.26-winx64\
datadir=D:\mysql-5.7.26-winx64\data
net_buffer_length=5242880
max_allowed_packet=104857600
bulk_insert_buffer_size=104857600
max_connections = 1000
innodb_flush_log_at_trx_commit = 2
# 本場景下測試MyISAM比InnoDB 提升1倍左右 default-storage-engine=MyISAM general_log = 1 general_log_file=D:\mysql-5.7.26-winx64\logs\mysql.log innodb_buffer_pool_size = 36G innodb_log_files_in_group=2 innodb_log_file_size = 500M innodb_log_buffer_size = 50M sync_binlog=1 innodb_lock_wait_timeout = 50 innodb_thread_concurrency = 16 key_buffer_size=82M read_buffer_size=64K read_rnd_buffer_size=256K sort_buffer_size=256K myisam_max_sort_file_size=100G myisam_sort_buffer_size=100M transaction_isolation=READ-COMMITTED 復制代碼
Kettle優化
啟動參數優化
本機內存較大,為了防止OOM,所以調大內存參數,創建環境變量 PENTAHO_DI_JAVA_OPTIONS
= -Xms20480m -Xmx30720m -XX:MaxPermSize=1024m
起始20G,最大30G
表輸入和表輸出開啟多線程
表輸入如果開啟多線程的話,會導致數據重復。比如 select * from test
,起3個線程,就會查3遍,最后的數據就是3份。肯定不行,沒達到優化的目的。
因為source是oracle,利用oracle的特性: rownum
和函數: mod
,以及kettle的參數: Internal.Step.Unique.Count,Internal.Step.Unique.Number
select * from (SELECT test.*,rownum rn FROM test ) where mod(rn,${Internal.Step.Unique.Count}) = ${Internal.Step.Unique.Number} 復制代碼
解釋一下
- rownum 是oracle系統順序分配為從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,意味着,如果排序字段或者數據有變化的話,rownum也會變(也就是跟物理數據沒有對應關系,如果要對應關系的話,應該用rowid,但是rowid不是數字,而是類似 AAAR3sAAEAAAACXAAA 的編碼),所以需要對rownum進行固化,所以將
SELECT test.*,rownum rn FROM test
作為子查詢 - mod 是oracle的取模運算函數,比如,
mod(5,3)
意即5%3=2
,就是5/3=1...2
中的2,也就是如果能獲取到總線程數,以及當前線程數,取模,就可以對結果集進行拆分了。mod(行號,總線程數)=當前線程序號
- kettle 內置函數
${Internal.Step.Unique.Count}
和${Internal.Step.Unique.Number}
分別代表線程總數和當前線程序號
而表輸出就無所謂了,開多少線程,kettle都會求總數然后平攤的。

右鍵選擇表輸入或者表輸出,選擇
改變開始復制的數量...
注意,不是一味的調大就一定能提升效率,要進行測試的。
表輸入時,注意勾選替換變量


- 修改提交數量(默認100,但是不是越大越好)
- 去掉裁剪表,因為是多線程,你肯定不希望,A線程剛插入的,B給刪掉。
- 必須要指定數據庫字段,因為表輸入的時候,會多一個行號字段。會導致插入失敗。當然如果你在創建表時,多加了行號字段,當做自增id的話,那就不需要這一步了。
- 開啟批量插入

Note: 通過開啟多線程,速度能提升5倍以上。
開啟線程池及優化jdbc參數



運行觀察結果

注意調整不同的參數(線程數,提交數),觀察速度。
其余提升空間
- 換ssd
- 繼續優化mysql參數
- 換引擎,比如,tokudb
- 換抽取工具,比如streamsets,datax
- 換數據庫,比如 clickhouse,tidb,Cassandra
- kettle集群
作者:趙安家
鏈接:https://juejin.im/post/5d0087f9f265da1bd6059cc1
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。