採用Kettle分頁處理大資料量抽取任務
需求:
將Oracle資料庫中某張表歷史資料匯入MySQL的一張表裡面。
源表(Oracle):table1
目標表(MySQL):table2
資料量:20,000,000
思路:
由於伺服器記憶體資源有限,所以,無法使用Kettle一次性從源表匯入目標表千萬級別的資料,考慮採用分頁匯入的方式來進行資料傳輸,即:
根據實際情況設定一個每次處理的資料量,比如:5,000條,然後根據總的資料條數和每次處理的資料量計算出一共分幾頁,
假設總資料量有:20,000,000,所以頁數為:20,000,000/5,000=4,000頁
注: 若存在小數,小數部分算一頁,比如:20.3算21頁
步驟:
根據需求的條件,首先對資料進行分頁:
資料量:20,000,000
每頁資料量:5,000
頁數:4,000
源表(Oracle):table1
目標表(MySQL):table2
主流程:transfer_table1_to_table2.kjb
流程說明:
transfer_table1_to_table2.kjb: 主流程
build_query_page.ktr: 構造頁數遊標
loop_execute.kjb: 根據頁數來執行資料匯入操作
我們分別來看各個部分的構成:
build_query_page.ktr: 構造頁數遊標
這一步中,我們需要構造一個類似這樣的資料結構:
其中P_PAGE是表頭,其餘為頁碼數,
注: 在這裡取頁碼數我通過這個表的rownum來構造
SQL:
select rownum as P_PAGE from mds.mds_balances_hist where
具體實現如下圖:
loop_execute.kjb: 根據頁數來執行資料匯入操作
在上一步中,我們構造了頁數,在這步中,我們遍歷上一步中的頁碼數,通過頁碼數找出相應的資料集進行操作,
其中包括set_values.ktr和execute_by_page.ktr兩個轉換
loop_execute.kjb具體實現如下:
set_values.ktr:表示獲取從上一步中獲得的頁數
execute_by_page.ktr:表示根據頁數進行資料匯入操作
其中query_by_page採用Oracle經典三層巢狀分頁演算法:
SELECT b.rn,b.* FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM table1) A
WHERE ROWNUM <= (${VAR_P_PAGE}*5000)
) b
WHERE RN >= ((${VAR_P_PAGE}-1)*5000+1)
注: ${VAR_P_PAGE}為每次獲取的頁碼數。
select_field為設定需要匯入的列名:
output_target目的是輸出到目標表table2:
因為要遍歷上一次執行的結果,那麼需要在transfer_table1_to_table2.kjb的loop_execute.kjb中做如下設定:
最後,執行transfer_table1_to_table2.kjb即可。
總結:
通過上述方法,我們可以很好的解決記憶體不足的情況下,大資料量在不同的資料庫之間的匯入工作。
FAQ:
- 在Kettle匯入大量資料的過程中,可能會出現連線斷開的現象:
http://forums.pentaho.com/showthread.php?74102-MySQL-connection-settings-at-java-level
(Idle connection timeout if we keep kettle idle for 8hours).
解決辦法:
原文地址: http://greyzeng.com/2016/10/31/big-data-etl/