2

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

插入设备没有问题,但是,检索它们是完全不同的故事。使用一个简单的 MySQL SELECT,我可以在几秒钟内得到它们,而 WiFi 是主要的瓶颈。但是,如果我尝试通过 Doctrine 获取它们,即使我允许 PHP 高达 1 GB,它也会耗尽内存。根据文档,我已经为 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);
}
4

2 回答 2

3

You're pulling in 300k objects, it'll consume way too much memory, try processing in chunks...

$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;
}
于 2012-05-25T16:18:20.030 回答
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文档,“使用 fetch-join 集合值关联的查询无法迭代结果” - 我认为这意味着内置方法,例如 findBy()。

请注意注释掉的 setFirstResult() 和 setMaxResults() 可用于偏移和限制。

于 2015-01-22T10:18:46.213 回答