我在获取实体集合时遇到了内存问题-。我使用的是PHP7.4、Symfony 5.4、Doctrine 2.7.5、API Platform 2.7Attachment
类有以下字段:
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Message", inversedBy="attachment")
*/
private Collection $messages;
使用经典的getter和setter。
在Doctrine中的QueryCollectionExtension中,我添加了:
private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
$queryBuilder
->andWhere('a.messages is not empty')
// breaks when preparing to execute this query
然后我得到这个错误
Error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 249856 bytes)" at /vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php line 138
{"exception":"[object] (Symfony\\Component\\ErrorHandler\\Error\\OutOfMemoryError(code: 0)
我的怀疑是,有附件是在数千条消息中发送的。当您尝试访问这些附件时,您会得到一个在$attachment->getMessages()
中有数千个Message
实体的实体
而在一个查询中,它的中断看起来像这样:
AND (
SELECT
COUNT(*)
FROM
attachment_message p4_
WHERE
p4_.attachment_id = p2_.id
) > ?
如果没有该部分,查询运行缓慢,但没有任何问题。
有没有人有一些解决方案,如何优化这一点,而不重组实体?
1条答案
按热度按时间vshtjzan1#
教条不能为您提供开箱即用的所有用例,特别是当您在多对多关系中拥有大量数据时。
但是你可以自己解决这个问题。有几种方法可以做到这一点。如果你还没有做过,你还需要优化你的数据库。例如,你需要
attachment_id
和message_id
上的索引。我希望Doctrine在迁移时生成它们,但最好检查一下以防万一。一些可能的解决方案:
1.限制水合作用:与其完全水合实体,不如考虑使用部分水合甚至选择来仅获取实际需要的列。2这可以在处理大型集合时保存大量内存。
1.使用
getArrayResult()
方法而不是getResult()。这将给予数组而不是对象,这样可以更有效地利用内存。1.使用分页。你真的需要所有的数据在这一点上?
1.而最灵活的解决方案-使用原生查询。您可以为原生查询设置自己的水化,以使用数据填充实体。例如,您可以像这样使用查询:
它根本不会获取消息,只是获取附件。