symfony 多对多连接中的实体太多,实体内存不足

sigwle7e  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(96)

我在获取实体集合时遇到了内存问题-。我使用的是PHP7.4、Symfony 5.4、Doctrine 2.7.5、API Platform 2.7
Attachment类有以下字段:

/**
 * @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
          ) > ?

如果没有该部分,查询运行缓慢,但没有任何问题。

有没有人有一些解决方案,如何优化这一点,而不重组实体?

vshtjzan

vshtjzan1#

教条不能为您提供开箱即用的所有用例,特别是当您在多对多关系中拥有大量数据时。
但是你可以自己解决这个问题。有几种方法可以做到这一点。如果你还没有做过,你还需要优化你的数据库。例如,你需要attachment_idmessage_id上的索引。我希望Doctrine在迁移时生成它们,但最好检查一下以防万一。
一些可能的解决方案:
1.限制水合作用:与其完全水合实体,不如考虑使用部分水合甚至选择来仅获取实际需要的列。2这可以在处理大型集合时保存大量内存。
1.使用getArrayResult()方法而不是getResult()。这将给予数组而不是对象,这样可以更有效地利用内存。
1.使用分页。你真的需要所有的数据在这一点上?
1.而最灵活的解决方案-使用原生查询。您可以为原生查询设置自己的水化,以使用数据填充实体。例如,您可以像这样使用查询:

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

它根本不会获取消息,只是获取附件。

相关问题