I\'ve got a basic codeset like this (inside a controller):
$sql = \'select * from someLargeTable limit 1000\';
$em = $this->getDoctrine()->getManager();
$c
I just ran into the same problem and wanted to share a possible solution. Chances are your DBAL uses PDO library and its PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
set to true which means all the results in your query are cached on mysql side and buffered into memory by PDO even though you never call $statement->fetchAll()
. To fix this, we just need to set PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
to false but DBAL does not give us a way to do it - its PDO connection class is protected without a public method to retrieve it and it does not give us a way to use setAttribute on the PDO connection.
So, in such situations, I just use my own PDO connection to save memory and speed things up. You can easily instantiate one with your doctrine db parameters like this:
$dbal_conn = $this->getDoctrine()->getManager()->getConnection();
$params = $dbal_conn->getParams();
$pdo_conn = new \PDO(
'mysql:dbname='.$dbal_conn->getDatabase().';unix_socket='.$params['unix_socket'],
$dbal_conn->getUsername(),
$dbal_conn->getPassword()
);
$pdo_conn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
I am using unix sockets but IP host addresses can also be easily used.
You can disable query buffer by doctrine config param options
doctrine:
dbal:
# configure these for your database server
driver: 'pdo_mysql'
...
options:
1000: false
The selected answer is wrong and @kroky's answer should be selected as the correct one.
The problem is Buffer vs Unbuffered Queries.
Now it won't be a good idea to change the behaviour for all queries, because:
Unless the full result set was fetched from the server no further queries can be sent over the same connection.
Hence, it should only be used when necessary. Here is a full working example with >200k objects:
$qb = ...->createQueryBuilder('p');
$this
->em
->getConnection()
->getWrappedConnection()
->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$query = $qb->getQuery();
$result = $query->iterate();
$batchSize = 20;
$i = 0;
foreach ($result as $product)
{
$i++;
var_dump($product[0]->getSku());
if (($i % $batchSize) === 0) {
$this->em->flush();
$this->em->clear(); // Detaches all objects from Doctrine!
}
}
It most likely needs some refinement.