在无缓冲查询的上下文中,foreach是等效的吗?

时间:2015-09-05 20:47:54

标签: php mysql pdo

我想知道 - 如果这段代码:

// example 1
$statement = $pdo->query('SELECT * FROM table'); // MySQL
while ($row = $statement->fetch())
{
  // doing something interesting
}

相当于此代码:

// example 2
$statement = $pdo->query('SELECT * FROM table'); // MySQL
foreach ($statement as $row)
{
  // doing something interesting
}

在MySQL中的无缓冲查询上下文中? (我知道循环给出相同的结果。)

或换句话说:

我尝试过类似的东西:

General error: 2014 Cannot execute queries while other unbuffered queries are active.

  1. 如果$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $statement = $pdo->query('SELECT * FROM table WHERE x = 1'); while(...) OR foreach(...) { // some magic } OR $statement->fetch(); // just fetch(), not fetchAll() $statement = $pdo->query('SELECT * FROM table WHERE x = 2'); // MySQL ... while代码运行没有错误。
  2. 如果只是foreach,我应该得到fetch()
  3. 所以看来,我回答了自己的问题;)但我还是不确定。我也找不到任何可以回答我问题的文档或SO问题。

2 个答案:

答案 0 :(得分:1)

PHP 5.5.12,Windows

我做了一些测试。我创建了一个包含100 000条记录的表,并检查了当表中的所有值用不同的方法求和时会占用多少内存:

+----------+-------------+--------+
| method   | memory used | time   |
+----------+-------------+--------+
| fetchAll | 69.9157 MB  | 7.20 s |  // <-- fails if memory_limit < 69 M
| while    | 0.2494 MB   | 3.24 s |
| foreach  | 0.2494 MB   | 0.98 s |  // <-- here I disagree with Ollie
+----------+-------------+--------+

考虑到我的问题和上述测试的测试,我得出结论:

  • 使用foreachwhile 等同于缓冲查询:两种方法逐行读取并在执行循环之后全部以这种方式获取数据,下一个查询不会抛出error 2014
  • foreach在迭代fetchAll之前不执行PDOStatement之类的操作来获取整个结果集:如果确实如此,那么memory_limit < 69M时测试会失败(恕我直言:它是相当逻辑,'因为PDOStatement实现Traversable接口)。所以我不同意Ollie Jones的回答(至少在我的电脑和环境中)。

答案 1 :(得分:-1)

正如您所观察到的,在php foreach中可以处理数组。因此,当您在pdo结果集上使用它时,pdo实现必须首先使结果集黯然失色。这样就完成了无缓冲的查询,并吸收了RAM。

最新版本的C#语言支持在数据流上处理foreach的能力。但是在php中你需要使用while ($row = fetch())构造。