作者:Grey
原文地址: http://www.cnblogs.com/greyzeng/p/5524614.html
需求:
將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 rownum<=4000
具體實現如下圖:
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).
解決辦法:
文章列表