Doctrine findBy()内存不足错误

时间:2012-05-25 15:05:59

标签: php memory doctrine doctrine-orm

我有一个包含大约300k行的表,用于描述Apple推送通知服务的设备。我使用Doctrine 2作为ORM。

插入设备没有问题,但是,检索它们是完全不同的故事。使用简单的MySQL SELECT我可以在几秒钟内获得它们,其中WiFi是主要的瓶颈。但是,如果我尝试通过Doctrine获取它们,即使我允许PHP高达1千兆字节,它也会耗尽内存。根据文档,我已经为Doctrine实体创建了getter和setter以及受保护的属性。

我不知道我做错了什么。这很好:

$devices = mysql_query("SELECT * FROM `Devices` WHERE `deviceProperty`='someValue'");

$message = new Message();
while($device = mysql_fetch_array($devices))
{
    $message->addRecipient($device['pushToken']);
}

但是第一行的内存不足(它永远不会到达下一行的断点):

$devices = self::$entityManager->getRepository('Device')->findBy(array("deviceProperty" => "someValue"));
$message = new Message();
foreach($devices as $device)
{
    $message->addRecipient($device->getPushToken);
}

2 个答案:

答案 0 :(得分:2)

你正在吸引300k对象,它会消耗太多内存,尝试处理大块...

$message = new Message();

$limit = 50;
$offset = 0;
while($devices = self::$entityManager->getRepository('Device')->findBy(array("deviceProperty" => "someValue"), array(), $limit, $offset))
{
   foreach($devices as $device)
   {
       $message->addRecipient($device->getPushToken);
   }
   $offset += $limit;
}

答案 1 :(得分:0)

如果你正在使用DQL,你可以使用iterate()函数迭代结果并在处理后刷新每个结果:

$message = new Message();
$cleaner = 0;

$q = self::$entityManager->createQuery(
    'SELECT d from Device d
     WHERE
     d.deviceProperty = :devicePropertyValue
    ');
$q->setParameter('devicePropertyValue', 'someValue');
//$q->setFirstResult(10000);
//$q->setMaxResults(5000);

$devices = $q->iterate();

foreach ($devices as $row) {
    $device = $row[0];

    $message->addRecipient($device->getPushToken);

    self::$entityManager->detach($device);

    if ($cleaner++ > 100) {
        self::$entityManager->clear();
        $cleaner = 0;
    }

}

对于我正在运行的批量重建索引作业,这将我的内存需求从3GB降低到256M以下。

根据Doctrine documentation,“使用fetch-join集合值关联的查询无法迭代结果” - 我认为这意味着内置方法,例如findBy()。

请注意已注释掉的setFirstResult()和setMaxResults(),您可以将其用于偏移和限制。