从大型PostgreSQL表中选择数据时,Perl脚本失败

时间:2014-02-22 20:30:03

标签: perl postgresql memory fetch

我正在尝试在PostgreSQL数据库上运行SELECT语句并将其结果保存到文件中。

代码在我的环境中运行但在轻量级服务器上运行后失败。

我对它进行了监控,发现它在几秒钟后失败的原因是由于内存不足(机器只有512MB RAM)。我不认为这是一个问题,因为我想要做的就是将整个结果集保存为磁盘上的JSON文件。

我计划使用fetchrow_arrayfetchrow_arrayref函数,希望一次只能获取和处理一行。

不幸的是,当您使用fetchall_arrayref时,我发现上述两者和DBD::Pg之间的真正提取操作没有区别。我的脚本在$sth->execute()调用失败,即使它有机会调用任何fetch...函数。

这告诉我,executeDBD::Pg的实现实际上将所有行都提取到内存中,只留下实际格式返回到fetch...函数。

快速查看DBI documentation会给出一个提示:

  

如果驱动程序支持SELECT语句的本地行高速缓存,则此属性保存高速缓存中未取出的行数。如果驱动程序没有,则返回undef。请注意,某些驱动程序在执行时预取行,而其他驱动程序则等到第一次获取时。

所以理论上我只需要设置RowCacheSize parameter。我尝试了这个功能doesn't seem to be implemented by DBD::Pg

  

DBD :: Pg

未使用

我发现这个限制是一个巨大的普遍问题(execute()调用pre-fetches 所有行?)并且更倾向于认为我在这里遗漏了一些东西,而不是这个使用Perl与PostgreSQL数据库交互的真正限制。


更新(2014-03-09):我的脚本现在可以运行了,这要归功于我对Borodin答案的评论中所描述的解决方法。 DBD::Pg库的维护者回答我的问题,实际上说根本原因更深,位于libpq postgresql内部库(由DBD::Pg使用)内。此外,我认为与此处描述的问题非常相似的问题会影响pgAdmin。作为postgresql本机工具,它仍然没有在Options中给出定义结果集行大小的默认限制的机会。这可能就是为什么Query tool有时会在显示庞大查询结果之前等待很长时间,在某些情况下可能会破坏应用程序。

1 个答案:

答案 0 :(得分:1)

section Cursors中,数据库驱动程序的文档说明了这个

  

因此"执行"方法一次将所有数据提取到位于前端应用程序中的数据结构中。选择大量数据时必须考虑这个事实!

所以你的假设是正确的。然而,同一部分继续描述您如何在Perl应用程序中使用游标来读取块中的数据。我相信这会解决你的问题。

另一种方法是在OFFSET语句中使用LIMITSELECT子句来模拟游标功能。如果你写

my $select = $dbh->prepare('SELECT * FROM table OFFSET ? LIMIT 1');

然后你可以说(所有这些都是未经测试的)

my $i = 0;
while ($select->execute($i++)) {
  my @data = $select->fetchrow_array;
  # Process data
}

一次读取一行表格。

您可能会发现需要增加块大小以获得可接受的效率水平。