在Postgres / PHP / PDO中迭代结果集的最佳实践?

时间:2011-10-24 15:36:11

标签: php postgresql pdo

我正在使用PHP 5.3.6和PDO访问Postgres 9.0.4。我被要求减少报告的内存占用。当前的实现很简单:执行查询,执行fetchAll(),然后通过生成的数组使用foreach()进行迭代。这显然无法扩展到巨大的结果集:它可以暂时消耗100MB或更多。

我有一个新的实现,它接受PDO语句句柄,然后使用foreach()直接迭代它,即没有通过fetchAll()的中间数组。 (根据我的阅读,使用foreach调用fetch()迭代语句句柄。)这同样快,消耗方式更少的内存:大约28kB。尽管如此,我并不自信我做得对,因为虽然我已经完成了大量的谷歌搜索,但很难找到有关此问题的基本问题的答案:

  • 我见过的文章建议使用游标来解决我原来的问题。 Postgress PDO驱动程序是否已在内部使用游标?如果需要编写我自己的SQL来创建游标,我愿意,但我更愿意编写最简单的代码(但不是更简单!)。

  • 如果foreach每次迭代调用fetch(),那网络聊得不是太多了?或者它是否智能并且一次取出许多行,例如500,节省带宽? (这可能意味着它在内部使用游标。)

  • 我见过一篇文章,它在实现Iterator接口的类中包装了语句句柄。鉴于PDO语句句柄已经执行此操作,这不是多余的吗?或者我错过了什么?

  • 我准备SQL语句的调用如下所示:

    $ sth = $ dbh-> prepare($ sql);

如果我这样做,我发现没有记忆或速度差异:

$sth = $dbh->prepare($sql, array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );

这是因为这是Postgres PDO驱动程序的默认设置吗?如果它已经在内部使用游标,这将是有意义的。

欢迎使用有关解决此问题的方法和其他方法的一般性评论。

2 个答案:

答案 0 :(得分:1)

Postgres的PDO does use cursors internally

答案 1 :(得分:0)

显然PDO::CURSOR_FWDONLY不使用游标。黑匣子测试:

(0)准备工作:

$con = new \PDO('dsn');
// you'll get "NO ACTIVE TRANSACTION" otherwise
$con->beginTransaction();

$sql = 'select * from largetable';

(1)默认 - 永远:

$stmt = $con->prepare($sql);
$stmt->execute();
print_r($stmt->fetch());

(2)FWDONLY - 永远:

$stmt = $con->prepare($sql, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY));
$stmt->execute();
print_r($stmt->fetch());

(3)SCROLLABLE - 快速运行:

$stmt = $con->prepare($sql, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_SCROLL));
$stmt->execute();
print_r($stmt->fetch());

我打开PG记录只是为了确定它确实如此 - 只有SCROLL使用游标。

因此,使用游标的唯一方法是使用SCROLL,至少在PHP 5.4.23中。