Sar*_*rel 3 pdo large-data symfony doctrine-orm dbal
我有一个这样的基本代码集(在控制器内):
$sql = 'select * from someLargeTable limit 1000';
$em = $this->getDoctrine()->getManager();
$conn = $em->getConnection();
$statement = $conn->prepare($sql);
$statement->execute();
Run Code Online (Sandbox Code Playgroud)
我的困难在于,当结果集只有几条记录时,内存使用情况并没有那么糟糕.我在运行$ statement-> execute()之前和之后回显了一些调试信息.部分代码,并为我的实现找到了我有以下内容:
pre-execute... rowCount :: 0 memory: 49.614 MB
post-execute... rowCount :: 1000 memory: 50.917 MB
Run Code Online (Sandbox Code Playgroud)
将其从1000条记录中移动到10k时,MB使用率的差异将增加到13 MB
pre-execute... rowCount :: 0 memory: 49.614 MB
post-execute... rowCount :: 10000 memory: 62.521 MB
Run Code Online (Sandbox Code Playgroud)
最终,检索大约50k记录,我接近我的最大内存分配:
pre-execute... rowCount :: 0 memory: 49.614 MB
post-execute... rowCount :: 50000 memory: 114.096 MB
Run Code Online (Sandbox Code Playgroud)
通过这种实现,我无法编写一个允许我检索数据CSV的控制器(甚至命令).当然,50k +条目听起来很多,问题就是为什么,但这不是问题.
我的最终问题是:在执行时,是否可以告诉DBAL/Connection或DBAL/Statement缓冲SQL内部的数据而不是整个PHP中的数据.例如,如果我有1000万行,只发送第一个说10k行到PHP ...让我通过@ statement-> fetch(); 当光标到达10k的末尾时,截断数组并从数据库中获取下一个10k?
kro*_*oky 12
我刚遇到同样的问题,想分享一个可能的解决方案.有可能你的DBAL使用PDO库并将其PDO::MYSQL_ATTR_USE_BUFFERED_QUERY设置为true,这意味着你的查询中的所有结果都缓存在mysql端并由PDO缓冲到内存中,即使你从未调用过$statement->fetchAll().要解决这个问题,我们只需要设置PDO::MYSQL_ATTR_USE_BUFFERED_QUERY为false,但是DBAL没有给我们一个方法 - 它的PDO连接类受到保护而没有公共方法来检索它,它没有给我们一种在PDO上使用setAttribute的方法连接.
因此,在这种情况下,我只使用自己的PDO连接来节省内存并加快速度.您可以使用您的doctrine db参数轻松实例化一个,如下所示:
$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);
Run Code Online (Sandbox Code Playgroud)
我使用的是unix套接字,但也可以很容易地使用IP主机地址.
选择的答案是错误的,@ kroky的答案应该被选为正确答案.
问题是缓冲区与未缓冲的查询.
现在,更改所有查询的行为不是一个好主意,因为:
除非从服务器获取完整结果集,否则无法通过同一连接发送进一步的查询.
因此,它只应在必要时使用.这是一个包含> 200k对象的完整工作示例:
$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!
}
}
Run Code Online (Sandbox Code Playgroud)
它很可能需要一些改进.
| 归档时间: |
|
| 查看次数: |
4439 次 |
| 最近记录: |