有哪些解决方案可以避免Doctrine2中的聚合计数字段中的select(n + 1)问题?

时间:2014-08-29 01:44:31

标签: symfony doctrine-orm doctrine

我有两个实体,User和Place,并且它们之间有多对多的关系,以便于用户喜欢某个地方的概念。

作为该功能的一部分,我希望Place实体包含一个字段,该字段为我提供了已经收藏它的用户总数。我自己不需要用户实体。

阅读文档后,我找到了几种解决方案,但我并不特别喜欢它们。

汇总字段

使用此解决方案,我只需在Venue实体上定义一个整数字段,在添加和删除收藏夹时更新该字段。因此,该值不是在运行中计算的,而是与任何其他字段一样被检索。

我不喜欢这种方法,因为并发存在问题,这使得在代码中管理这个概念变得非常复杂。

急切加载

使用这种方法,我会急切地将关系加载为双向关联,以便Place将加载每个在初始查询过程中已经收藏它的用户实体。为了获得计数,我只是询问集合的计数()。

这样可以减少查询次数,但检索到的数据量太多,而且随着时间的推移不能很好地扩展。

延迟加载

这就是我目前正在使用的内容。它与Eager Loading解决方案类似,我确保关系是双向的,只是询问集合的count(),但使用额外的延迟获取模式doctrine足够智能,只发出COUNT()查询而不是检索与Place实体关联的整个用户列表。

这里的缺点是,如果我加载N Place实体,我需要N + 1个查询,因为每个Place都会发出一个单独的COUNT()查询。

理想解决方案

我理想的解决方案是找到一种方法来告诉Doctrine执行第一个查询来加载集合,然后第二个查询来加载集合中ID的所有计数,然后填充各自实体中的字段。 / p>

我还没有找到办法轻松做到这一点。

有没有人有任何这方面的例子,或者是否有其他解决方案来解决我可能会忽略的问题?

2 个答案:

答案 0 :(得分:0)

如果您知道如何在sql中编写查询,则可以在doctrine中进行。

请参阅此答案以供参考: Symfony2, Doctrine2 query - select with IF and COUNT

答案 1 :(得分:0)

您可以运行类似的DQL:

SELECT p place, COUNT(u) cnt FROM YourBundle:Place p
                LEFT JOIN p.users u

请注意,结果数组元素在表单中(每个都是一个数组):

array(
 'place' => your hydrated object (in your case the place),
 'cnt' => your aggregated field (in your case the number of users),
)