2016-06-13 34 views
2

我可以在36秒內使用Matlab的DB工具箱導入200萬行。如何在20分鐘內導入600萬行?從SQL數據庫導入數據到MATLAB:2密爾行需要30秒,但6密爾需要21分鐘?

以下查詢的最終提取步驟大約需要36秒。

q = 'select ... from mytable limit 2000000'; %notice 2 mil limit 
result = exec(conn, q); 
final_result = fetch(result); % Takes about 36 seconds. 

我的整個表格有6,097,227行。 但是,如果我做的:

q = 'select ... from mytable'; 
result = exec(conn, q); 
final_result = fetch(result); 

MATLAB 完全失去了它最終取一步! CPU使用率約爲500-600%(即正在使用6/8個內核),並且需要永久使用。目前,它設置爲10k批次,最終在21分鐘內完成。

想法?該怎麼辦?我真的很努力地想知道這在行數上如何不至少是線性的。我是否跨過了一些奇怪的限制?

順便說一句:整個查詢和導入到R使用PostgreSQL驅動程序等在R中需要大約43秒...和0擺弄。我可以使用ODBC在類似的時間導入Stata。

注意:在上面的查詢中...是10個左右的數字變量:一些整數,一些雙精度。沒有文字。

+0

你可以使用Node.js來進行導入嗎? –

+0

@ vitaly -t我真的不知道Node.js在這裏如何應用? (我編輯了一下這個問題,我可能一直不清楚。) –

+0

在這種情況下,我只能在一般情況下提出建議,正如我在下面的答案中所做的那樣。 –

回答

1

如果任何人遇到在未來這種類型的問題,我已經找到了巨頭 1GB大小的查詢,它的速度更快,更穩健:

  1. 使用複製或類似寫的查詢結果到一個CSV文件。
  2. 將csv文件讀入Matlab(例如帶可讀的)。
1

這是爲像這樣的大型進口的一般戰略提供建議。如果你使用的任何組件都沒有遵循它,那麼你自然會遇到問題。

首先,根據記錄的平均大小,批量導入1,000到10,000條記錄中的記錄。

其次,插入每批有一個多行INSERT

INSERT INTO TABLE(columns...) VALUES (first-insert values), (second-insert values),... 

即串聯所有的每批記錄到一個單一的多行插入並執行它的方式。它將爲IO提供巨大的節約。

7

首先,我建議您嘗試增加Java堆內存大小。其次,在導入/導出大量數據的情況下,似乎Matlab Database Toolbox可能不是PostgreSQL的高效連接器。這可以通過原生Matlab格式的重要數據轉換開銷來解釋。減少這種開銷的方法之一是遵循http://undocumentedmatlab.com/blog/speeding-up-matlab-jdbc-sql-queries中提出的解決方案。但是JDBC本身有一些無法解決的限制。這是在下面的圖片很好的說明(事實上,這些照片是對數據的插入,而不是數據檢索不會改變任何東西的開銷是存在的,不管你通過數據哪個方向):

The case of scalar numeric data The case of arrays

這裏fastinsertdatainsert性能與batchParamExec 從PgMex之一(見https://pgmex.alliedtesting.com/#batchparamexec瞭解詳細信息)進行比較。第一張圖片用於標量數字數據,第二張圖片用於數組。每個圖的端點對應於 到通過相應的方法傳遞到數據庫中的某個最大數據量而沒有任何錯誤。 大於最大值(特定於每種方法)的數據量導致「Java堆內存不足」問題 (每個實驗的Java堆大小在每個圖的頂部指定)。 有關實驗的更多詳細信息,請參閱以下 "Performance comparison of PostgreSQL connectors in Matlab" article

這裏的主要原因是PgMex根本不使用JDBC,而是基於libpq,並且在Matlab和PostgreSQL之間提供100%的二進制數據傳輸,而無需任何文本解析。同時,所有的工作都通過Matlab友好的 和本地方式(以矩陣,多維數組,結構和任意其他Matlab格式的形式)完成,因此,不會將Java對象轉換爲Matlab格式。

關於數據檢索的情況,初步實驗表明,PgMex比Matlab數據庫工具箱快大約3.5倍,用於標量數值數據的最簡單情況。 這樣的代碼可以使用PgMex重寫,如下所示(我們假設以下所有標記爲<>的參數都被填充,查詢q固定爲正確,並且fieldSpecStr中的類型對應於已存在的mytable的類型相應的數據庫):

% Create the database connection 
dbConn = com.allied.pgmex.pgmexec('connect',[... 
    'host=<yourhost> dbname=<yourdb> port=<yourport> '... 
    'user=<your_postgres_username> password=<your_postgres_password>']); 

% Execute a query 
q = 'select ... from mytable'; 
pgResult = com.allied.pgmex.pgmexec('exec',dbConn,q); 

% Read the results 
nFields=com.allied.pgmex.pgmexec('nFields',pgResult); 
outCVec=cell(nFields,1); 
fieldSpecStr='%<field_type_1> %<field_type_2> ...'; 
inpCVec=num2cell(0:nFields-1); 
[outCVec{:}]=com.allied.pgmex.pgmexec('getf',pgResult,... 
    fieldSpecStr,inpCVec{:}); 

請另見http://pgmex.alliedtesting.com/#getf對有關的輸入 和輸出參數的格式命令getf細節(包括fieldSpecStr)。總而言之,outCVec 的每個元素包含具有字段valueVec,isNullVecisValueNullVec的結構。所有這些字段沿着第一維的大小爲 ,等於檢索的元組數,valueVec包含 各個表字段的值,而isNullVecisValueNullVec是NULL的指示符。