【问题标题】:Doctrine2: Limiting with Left Joins / Pagination - Best PracticeDoctrine2:使用左连接/分页进行限制 - 最佳实践
【发布时间】:2012-05-28 22:19:07
【问题描述】:

我有一个大查询(在我的查询生成器中)和很多左连接。所以我得到带有他们的 cmets 和标签等的文章。 假设我有以下 dql:

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

现在假设我的数据库有 100 多篇博文,但我只想要前 10 篇,但要包含这 10 篇的所有 cmets 及其所有标签(如果存在)。 如果我使用 setMaxResults 它会限制行数。所以我可能会得到前两个帖子,但最后一个缺少一些它的 cmets 或标签。所以followin不起作用。

$result = $em->createQuery($dql)->setMaxResults(15)->getResult();

使用几乎没有文档记录的 Pagination 随教义 2.2 提供的解决方案对我来说也不是很有效,因为它太慢了,我也可以加载所有数据。

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

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

【问题讨论】:

  • 请将您拥有的代码添加到您的问题中,甚至可以使用示例结果来显示您想要什么以及您得到什么。

标签: pagination doctrine-orm subquery database-performance query-builder


【解决方案1】:

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

Pagination

本教程更多的是关于分页而不是获得前 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

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

【讨论】:

    【解决方案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。
    • 我不喜欢使用 DABL/ORM 框架然后仍然使用本机查询。对我来说没有多大意义。
    • 那么看起来您需要进行两个查询。我同意应该有更好的方法来限制和页面连接的结果。
    猜你喜欢
    • 2015-10-19
    • 1970-01-01
    • 2015-03-25
    • 2012-12-02
    • 1970-01-01
    • 2011-05-26
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多