Reputation: 920
So, i'd been exposed to more and more real life application where:
SELECT * FROM table
is too heavy already, resulting to
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 47 bytes) in
.
What I am currently doing is splitting these mySQL rows into batches
, setting a variable $perPage
, then passing a $_GET['page']
variable to the page, something link: process.php?page=1
Which I think is "good". But sometimes, we want full automation. So I set $nextPage = (int) $_GET['page'] + 1
, then redirect the page to then iteration after processing these mySQL rows
header("Location: process.php?p="$nextPage)
Now, this would give you some issues:
process.php
with follow-redirect enabled.This is how I currently handle this, but sometimes thinking that I need to code more just to make it work is a bit frustrating. Does anyone know how to handle these more elegantly?
Upvotes: 3
Views: 2718
Reputation: 45490
Just process your rows one by one instead of collecting them all in array.
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
//process then release, do not store
}
If your processing requires an array, then there is a trick. PHP Generators would disguise a while loop as an array.
A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate. Instead, you can write a generator function, which is the same as a normal function, except that instead of returning once, a generator can yield as many times as it needs to in order to provide the values to be iterated over.
Using yield
(from C
) will allow you to achieve that.
Here is an example on how to implement it:
function getRecords()
{
$sql = 'SELECT field1, field2 FROM table';
$stmt = $this->conn->prepare($sql);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield $row;
}
}
foreach ($this->getRecords() as $record) {
//process then release, do not store
}
However, it wouldn't make much sense, as PDOStatement is already Traversable (frankly, uses the same trick as generators) and you can have this function like this with same outcome
function getRecords()
{
$sql = 'SELECT field1, field2 FROM table';
$stmt = $this->conn->prepare($sql);
$stmt->execute();
return $stmt;
}
Notice:
SELECT *
can unnecessarily make you run out of memory.fetchAll()
would not work, because it will get all the rows at once.foreach
this defeats the purpose of generators.Upvotes: 7
Reputation: 1020
In a loop; get a piece of data from database do whatever you want, free memory with unset() function and then get next piece of data.
Upvotes: 0