我有一个包含大约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);
}
答案 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(),您可以将其用于偏移和限制。