我可以在大约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个数字变量:一些整数,一些双精度。没有文字。
答案 0 :(得分:6)
首先,我建议您尝试增加Java堆内存大小。其次,似乎Matlab数据库工具箱在导入/导出相当大量的数据的情况下可能不是PostgreSQL的非常有效的连接器。这可以通过本地Matlab格式的重要数据转换开销来解释。减少这种开销的方法之一是遵循http://undocumentedmatlab.com/blog/speeding-up-matlab-jdbc-sql-queries中提出的解决方案。但是JDBC本身具有某些无法解决的局限性。在下面的图片中很好地说明了这一点(图片是用于数据插入而不是数据检索的事实,因为无论您在哪个方向传递数据,都不会因为开销而改变任何内容):
此处fastinsert
和datainsert
的效果与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
的每一个要素
包含具有字段outCVec
,valueVec
和isNullVec
的结构。所有这些字段都有大小
沿着第一个维度等于重新获得的元组数,isValueNullVec
包含的值
相应的表字段,而valueVec
和isNullVec
是NULL的指示符。
编辑:PgMex的学术许可证是免费提供的。
答案 1 :(得分:1)
这是为像这样的大型进口的一般策略提供建议。如果您使用的任何组件未能遵循它,那么您自然会遇到问题。
首先,根据记录的平均大小,分批导入1,000到10,000条记录的记录。
其次,使用单个多行INSERT
插入每个批次:
INSERT INTO TABLE(columns...) VALUES (first-insert values), (second-insert values),...
即。将每个批次的所有记录连接到一个多行插入中并以这种方式执行。它将为IO提供巨大的节省。
答案 2 :(得分:0)
如果将来有人遇到此类问题,我发现巨型 1GB大小的查询,它更快,更强大: