从SQL数据库导入数据到MATLAB:2 mil行需要30秒,但6 mil需要21分钟?

时间:2016-06-13 20:51:16

标签: matlab postgresql

我可以在大约36秒内使用Matlab的DB工具箱导入200万行。如何在20分钟内导入600万行?

以下查询的最终获取步骤大约需要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分钟内完成。

想法?怎么办?我真的很难看到这个行如何至少与行数大致呈线性关系。我是否超越了一些奇怪的限制?

BTW:使用PostgreSQL驱动程序等在R中进行整个查询并导入到R大约需要43秒...并且0摆弄。我可以使用ODBC在类似的时间导入Stata。

注意:在上面的查询...中有大约10个数字变量:一些整数,一些双精度。没有文字。

3 个答案:

答案 0 :(得分:6)

首先,我建议您尝试增加Java堆内存大小。其次,似乎Matlab数据库工具箱在导入/导出相当大量的数据的情况下可能不是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被修正为正确,{{1}中的类型对应于相应数据库中已存在的fieldSpecStr类型:

mytable

有关输入格式的详细信息,另请参阅http://pgmex.alliedtesting.com/#getf 并输出命令% 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{:}); 的参数(包括getf)。简而言之,fieldSpecStr的每一个要素 包含具有字段outCVecvalueVecisNullVec的结构。所有这些字段都有大小 沿着第一个维度等于重新获得的元组数,isValueNullVec包含的值 相应的表字段,而valueVecisNullVec是NULL的指示符。

编辑:PgMex的学术许可证是免费提供的。

答案 1 :(得分:1)

这是为像这样的大型进口的一般策略提供建议。如果您使用的任何组件未能遵循它,那么您自然会遇到问题。

首先,根据记录的平均大小,分批导入1,000到10,000条记录的记录。

其次,使用单个多行INSERT插入每个批次:

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

即。将每个批次的所有记录连接到一个多行插入中并以这种方式执行。它将为IO提供巨大的节省。

答案 2 :(得分:0)

如果将来有人遇到此类问题,我发现巨型 1GB大小的查询,它更快,更强大:

  1. 使用COPY或类似方法将查询结果写入csv文件。
  2. 将csv文件读入Matlab(例如,可读表格)。