多对多连接中实体中的 Doctrine 内存不足

问题描述 投票:0回答:1

我在获取实体集合 - 附件时遇到内存问题。我正在使用 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
          ) > ?

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

有人有关于如何在不重组实体的情况下优化此问题的解决方案吗?

php symfony doctrine-orm doctrine api-platform.com
1个回答
0
投票

Doctrine 无法涵盖开箱即用的所有用例。特别是当您拥有大量多对多关系的数据时。

但是你可以自己解决问题。有几种方法可以做到这一点。如果您还没有这样做,您还需要优化您的数据库。例如,您需要

attachment_id
message_id
上的索引。我希望 Doctrine 在迁移中生成它们,但最好检查一下以防万一。

一些可能的解决方案:

  1. 限制水合:不要完全水合实体,而是考虑使用部分水合甚至选择仅获取您实际需要的列。在处理大型集合时,这可以节省大量内存。
  2. 使用
    getArrayResult()
    方法而不是 getResult()。这将为您提供数组而不是对象,这可以提高内存效率。
  3. 使用分页。此时您真的需要所有数据吗?
  4. 最灵活的解决方案 - 使用本机查询。您可以为本机查询设置自己的水合,以用数据填充实体。例如,您可以使用这样的查询:
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

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

© www.soinside.com 2019 - 2024. All rights reserved.