Doctrine2:左连接限制/分页 - 最佳实践

7
我可以帮助您进行翻译。以下是需要翻译的内容:

我在我的查询构建器中有一个很大的查询,以及许多左连接。因此,我可以获取带有其评论、标签等的文章。 假设我有以下DQL:

$dql = 'SELECT blogpost, comment, tags 
FROM BlogPost blogpost 
LEFT JOIN blogpost.comments comments
LEFT JOIN blogpost.tags tags';

现在假设我的数据库有100多篇博客文章,但我只想要前10篇,但是要包括这10篇文章的所有评论和标签(如果存在)。如果使用setMaxResults,则会限制行数。因此,可能会得到前两篇文章,但其中最后一篇文章缺少一些评论或标签。因此,以下方法不起作用。
$result = $em->createQuery($dql)->setMaxResults(15)->getResult();

使用难以找到文档的分页解决方案并不能满足我的需求,因为它太慢了,我可以一次性加载所有数据。
我尝试了Stackoverflow文章中的解决方案,但即使是那篇文章也缺乏最佳实践,并且所提供的解决方案非常缓慢。
难道没有一个最佳实践来解决这个问题吗? 难道没有人在生产模式下使用Doctrine2.2吗?

1
请将您所拥有的代码添加到问题中,最好附带示例结果以显示您想要的内容以及实际获取的内容。 - Gustav Bertram
2个回答

11
使用这样的查询获得正确的结果是有问题的。Doctrine网站上有一篇关于这个问题的教程。 分页 该教程更多地涉及分页而不是获取前5个结果,但总体思路是你需要执行“SELECT DISTINCT a.id FROM articles a ... LIMIT 5”而不是普通的SELECT查询。这比较复杂,但那篇教程中的最后两点应该会让你找到正确的方向。
更新:
问题不在于Doctrine或任何其他ORM。问题完全在于数据库能否返回您要求的结果。这就是连接的工作方式。
如果对查询进行解释,它将为您提供更详细的答案。将其结果添加到您的初始问题中是一个好主意。
在分页文章中,需要至少两个查询才能获得所需的结果。在查询中添加DISTINCT可能会显著减慢查询速度,但只有在其中使用连接时才真正需要它。您可以编写另一个查询,仅按创建日期顺序检索前10篇文章,而不进行连接。一旦获得了这10篇文章的ID,再进行另一个查询,包括连接和WHERE blogpost.id IN (...) ORDER BY blogpost.created。这种方法应该更有效率。
SELECT 
    bp 
FROM 
    Blogpost bp 
ORDER BY 
    bp.created DESC
LIMIT 10

由于在第一个查询中你只关心ID,因此可以设置Doctrine使用标量水合。

SELECT 
    bg 
FROM 
    Blogpost bp 
LEFT JOIN 
    bp.comments c 
LEFT JOIN 
    bp.tags t 
WHERE 
    bp.id IN (...) 
ORDER BY 
    bp.created DESC

你也可以使用相关子查询在一次查询中完成。关于子查询总是不好的说法是错误的。有时它们比连接更快。你需要实验来找出最适合你的解决方案。


2

在澄清问题后进行编辑:

您可以在本地MySQL中使用FROM子句中的子查询来实现所需的功能,例如:

SELECT * FROM 
 (SELECT * FROM articles ORDER BY date LIMIT 5) AS limited_articles, 
 comments, 
 tags 
WHERE
 limited_articles.article_id=comments.article_id
 limited_articles.article_id=tags.article_id

据我所知,DQL不支持像这样的子查询,因此您可以使用NativeQuery类。

不,我不想要我的N中最新的M。我想要最新的N,其中包含它们所有的M、X和Y。 - Andresch Serj
我不太喜欢使用DABL/ORM框架,然后仍然使用本地查询。这对我来说没有太多意义。 - Andresch Serj
1
那么看起来你需要进行两个查询。我同意应该有更好的方法来限制和分页连接的结果。 - Nicolas Renold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接