【问题标题】:Optimising eloquent query优化 eloquent 查询
【发布时间】:2014-03-07 01:07:32
【问题描述】:

我需要在一个雄辩的查询上附加一个自定义选择,但我发现整个事情有点难以理解。这涉及一个论坛系统,其中每个论坛对象需要知道注册了多少个主题关系和评论关系。这是我到目前为止所得到的:

在 Forum.php 中

public function getNumTopics () {
    return Topic::where('forum_id', '=', $this->id)->count();
}

public function getNumComments () {
    return Comment::wherein('topic_id', Topic::where('forum_id', '=', 1)->lists('id'));
}

控制器返回 json

public function getCategories () {
    $categories = ForumCategory::with('forums')->get();
    foreach ($categories as $cat) {
        if ($cat->forums->count() > 0) {
            foreach ($cat->forums as $forum) {
                /* @var $forum Forum */
                $forum->num_topics = $forum->getNumTopics();
                $forum->num_posts  = $forum->getNumComments();
            }
        }
    }
    return Response::json($categories, 200);
}

调用大约需要 1300 毫秒才能返回三个类别的 5 个论坛。我怀疑这是因为它执行了大约 16 个查询而不是一个。有没有办法将“num_topics”和“num_posts”作为属性附加到选择上,以便我只执行一个查询?

编辑

我基本上想要的是当我要求 Forum::all() 时,Eloquent 会产生这样的东西:

select f.*,
       ifnull(count(t.id), 0) num_topics,
       ifnull(count(c.id), 0) num_posts
  from forums f left join topics t on t.forum_id = f.id
                left join comments c on c.topic_id = t.id
 group by f.id

【问题讨论】:

  • 我要尝试优化的第一件事是运行两个查询的 getNumComments 函数。此外,您的 getNumtTopics 和 getNumComments 都运行基本相同的查询,Topic::where('forum_id'...
  • 我添加了我认为我希望 Eloquent 为我生成的查询。

标签: laravel eloquent


【解决方案1】:

您必须以任何一种方式查询这些表,因此最好的办法应该是急切加载所有内容并在检索到后对其进行计数,而不是为了查找计数而对数据库进行更多调用。

public function getCategories () {
    $categories = ForumCategory::with('forums.topics.comments')->get();
    foreach($categories as $category) {
        foreach($category->forums as &$forum) {
            $forum->num_topics = $forum->topics()->count();
            $forum->num_comments = 0;
            foreach($forum->topics as $topic) {
                $forum->num_comments += $topic->comments()->count();
            }
        }
    }

    return Response::json($categories, 200);
}

这会将num_topicsnum_comments 附加到每个Forum 对象。

调用次数更少,但它在一次扫描中获取更多信息,因此它可能更快或更慢,必须进行一些测试。好消息是,因为它可以抓取所有内容,所以不需要额外的查询。

【讨论】:

  • 对于大型数据集(这可能成为),像这样查询所有级别可能有点过分?或者 Laravel 是否在做一些我不知道的内部优化?在上面的问题编辑中查看我要生成的查询
  • 就性能而言,您发布的例程大约快 50 毫秒,并且在 1250 毫秒而不是 1300 毫秒内响应。这不是那么有回报... :-( 但我完全赞成减少通话...
猜你喜欢
  • 2018-05-27
  • 2021-07-22
  • 2020-12-17
  • 2017-11-14
  • 2017-10-07
  • 2020-09-24
  • 2018-02-27
  • 2019-06-28
  • 2018-07-25
相关资源
最近更新 更多