通过相关表格列订购表格的最快方法

时间:2019-06-18 04:42:21

标签: mysql sql laravel laravel-5.5 laravel-query-builder

我有2张桌子的注释和图片

我正在尝试先订购具有图像的评论,然后再订购不含图像的评论。

我在下面使用此查询解决了此问题,但是对于大数据来说它非常慢,大约需要12秒

$data = Comment::withCount([
        'images' => function ($query) use ($shop)
        {
            $query->where('shop_name', $shop);

        },
    ])->where('shop_name', $shop)->orderBy('images_count', 'desc')->paginate(10);

如何提高性能,或者是否有其他方法可以更快地获得相似的结果?

2 个答案:

答案 0 :(得分:1)

问题在于Laravel如何使withCount()起作用-它将生成如下内容:

SELECT `comments`.*, 
   (SELECT Count(*) 
    FROM   `images` 
    WHERE  `comment_id`.`id` = `comments`.`id` 
           AND `images`.`shop_name` = 'your shop') AS `images_count` 
FROM   `comments` 
WHERE  `shop_name` = 'your_shop' 
ORDER  BY `images_count` 

这将强制MySQL对指定商店的每个评论执行count()子查询。

您在这里需要做的是将这个 correlated 子查询(针对每一行执行)变成一个 independent 查询(仅执行一次),然后利用联接让MySQL全部配对:

$imagesCountQuery = DB::table('comments')
    ->selectRaw('comments.id AS comment_id, COUNT(comments.id) AS images_count')
    ->join('images', 'images.comment_id', '=', 'comments.id') /* !!! */
    ->where('images.shop_name', '=', $shop)
    ->groupBy('comments.id');

$data = Comment::joinSub($imagesCountQuery, 'images_count_sub', function ($join) {
    $join->on('comments.id', '=', 'images_count_sub'.'comment_id'); /* !!! */
})->where('shop_name', $shop)->orderBy('images_count_sub.images_count', 'desc')->paginate(10);

!!! -应该修改此行以表示您的评论的images关系。在此示例中,我假设这是hasMany关系,因为您没有在问题中指出这一点。

答案 1 :(得分:0)

您需要在Comment模型中创建hasMany关系。

class Comment extends \Eloquent {  

        public function images()
        {
            return $this->hasMany('Images', 'comment_id');
        } 
     }

现在您可以使用下面的查询来获取记录。

$comments = Comments::with('images')->get()->sortBy(function($comment)
    {
        return $comment->images->count();
    });