我正在尝试在PostgreSQL数据库上运行SELECT语句并将其结果保存到文件中。
代码在我的环境中运行但在轻量级服务器上运行后失败。
我对它进行了监控,发现它在几秒钟后失败的原因是由于内存不足(机器只有512MB RAM)。我不认为这是一个问题,因为我想要做的就是将整个结果集保存为磁盘上的JSON文件。
我计划使用fetchrow_array
或fetchrow_arrayref
函数,希望一次只能获取和处理一行。
不幸的是,当您使用fetchall_arrayref
时,我发现上述两者和DBD::Pg
之间的真正提取操作没有区别。我的脚本在$sth->execute()
调用失败,即使它有机会调用任何fetch...
函数。
这告诉我,execute
中DBD::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
有时会在显示庞大查询结果之前等待很长时间,在某些情况下可能会破坏应用程序。
答案 0 :(得分:1)
在section Cursors中,数据库驱动程序的文档说明了这个
因此"执行"方法一次将所有数据提取到位于前端应用程序中的数据结构中。选择大量数据时必须考虑这个事实!
所以你的假设是正确的。然而,同一部分继续描述您如何在Perl应用程序中使用游标来读取块中的数据。我相信这会解决你的问题。
另一种方法是在OFFSET
语句中使用LIMIT
和SELECT
子句来模拟游标功能。如果你写
my $select = $dbh->prepare('SELECT * FROM table OFFSET ? LIMIT 1');
然后你可以说(所有这些都是未经测试的)
my $i = 0;
while ($select->execute($i++)) {
my @data = $select->fetchrow_array;
# Process data
}
一次读取一行表格。
您可能会发现需要增加块大小以获得可接受的效率水平。