I am wondering -- if this code:
// example 1
$statement = $pdo->query('SELECT * FROM table'); // MySQL
while ($row = $statement->fetch())
{
// doing something interesting
}
is equivalent of this code:
// example 2
$statement = $pdo->query('SELECT * FROM table'); // MySQL
foreach ($statement as $row)
{
// doing something interesting
}
in context of unbuffered queries in MySQL? (I am aware the loops give the same results.)
Or in other words:
query
or prepare
right after the loop throws General error: 2014 Cannot execute queries while other unbuffered queries are active.
I tried something like that:
$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
...
And:
while
or foreach
the code runs without errors.fetch()
, I, as supposed, get error: 2014
.So it seems, that I answered my own question;) But I'm still not sure. I couldn't find any docs or an SO question that would answer my problem, either.
PHP 5.5.12, Windows
I did some more tests. I created a table with 100 000 records and I checked how much memory is taken when all values in the table are summed with different methods:
+----------+-------------+--------+
| 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
+----------+-------------+--------+
Taking into account the test from my question and the tests above, I conclude that:
foreach
and while
is equivalent in terms of buffering queries: both methods read row by row and after execution of the loop all data is fetched in such way, that a next query won't throw error 2014
foreach
does not do something like fetchAll
to get the whole resultset before iterating over PDOStatement
: if it did, the test would fail when memory_limit < 69M
(IMHO: it's quite logic, 'cause PDOStatement
implements Traversable
interface). So I cannot agree with Ollie Jones' answer (at least on my computer and environment).As you have observed, in php foreach
works on arrays. So, when you use it on a pdo resultset, it's necessary for the pdo implementation to slurp the resultset first. That completes the unbuffered query, and soaks up RAM.
The ability to handle foreach
on a stream of data is supported by recent versions of the C# language. But in php you need to use the while ($row = fetch())
construct.