我在获取实体集合 - 附件时遇到内存问题。我正在使用 PHP7.4、Symfony 5.4、Doctrine 2.7.5、APIPlatform 2.7
类
Attachment
有这个字段:
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Message", inversedBy="attachment")
*/
private Collection $messages;
具有经典的 getter 和 setter。
在 Doctrine、ApiPlatform 中的 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)
我怀疑有在数千条消息中发送了附件。当您尝试访问这些附件时,您会得到一个在
Message
中包含数千个
$attachment->getMessages()
实体的实体
在查询中它中断的地方看起来像这样:
AND (
SELECT
COUNT(*)
FROM
attachment_message p4_
WHERE
p4_.attachment_id = p2_.id
) > ?
没有该部分,查询运行缓慢,但没有任何问题。
有人有关于如何在不重组实体的情况下优化此问题的解决方案吗?
Doctrine 无法涵盖开箱即用的所有用例。特别是当您拥有大量多对多关系的数据时。
但是你可以自己解决问题。有几种方法可以做到这一点。如果您还没有这样做,您还需要优化您的数据库。例如,您需要
attachment_id
和 message_id
上的索引。我希望 Doctrine 在迁移中生成它们,但最好检查一下以防万一。
一些可能的解决方案:
getArrayResult()
方法而不是 getResult()。这将为您提供数组而不是对象,这可以提高内存效率。SELECT a.*
FROM attachment a
INNER JOIN attachment_message am ON a.id = am.attachment_id
GROUP BY a.id
HAVING COUNT(am.message_id) > 0
它根本不会获取消息,只会获取附件。