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();

使用doctrine2.2附带的几乎没有记录的分页解决方案对我来说也不是很有效,因为它太慢了,我也可以加载所有数据。

我尝试了Stackoverflow 文章中的解决方案,但即使该文章仍然缺少最佳实践,并且提出的解决方案非常缓慢。

没有关于如何做到这一点的最佳实践吗?没有人在生产模式下使用 Doctrine2.2 吗?

4

2 回答 2

11

使用这样的查询获得正确的结果是有问题的。Doctrine 网站上有一个教程解释了这个问题。

分页

本教程更多的是关于分页而不是获得前 5 个结果,但总体思路是您需要执行“SELECT DISTINCT a.id FROM article a ... LIMIT 5”而不是正常的 SELECT。它比这更复杂一些,但该教程中的最后 2 点应该让您走上正轨。

更新:

这里的问题不是 Doctrine 或任何其他 ORM。问题完全在于数据库能够返回您要求的结果。这就是连接的工作方式。

如果您对查询进行 EXPLAIN,它将为您提供有关正在发生的事情的更深入的答案。将结果添加到您的初始问题中将是一个好主意。

基于分页文章中讨论的内容,您似乎需要至少 2 个查询才能获得所需的结果。将 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 设置为使用 Scalar Hydration。

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

您也可以使用相关子查询在一个查询中执行此操作。子查询总是不好的神话是不正确的。有时它们比连接更快。您需要进行试验以找出最适合您的解决方案。

于 2012-06-08T00:42:46.130 回答
2

根据已澄清的问题进行编辑:

您可以使用 FROM 子句中的子查询在本机 MySQL 中执行您想要的操作,如下所示:

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 类。

于 2012-06-07T23:42:26.447 回答