我正在使用Laravel Eloquent模型创建一个非常基本的MySQL查询。我有三个数据库表:posts
,tags
和post_tag
(数据透视表)。我想得到并分页最常用的标签。查询正在运行,但加载大约需要30秒。 tags
表有~9k记录,post_tag
表有~26k记录。但在不久的将来,post_tag
表中的记录将超过100万条记录。
代码如下:
$tags = Tag::leftJoin('post_tag', 'tags.id', '=', 'post_tag.tag_id')
->select(\DB::raw('post_tag.tag_id, tags.content, COUNT(`tag_id`) AS `occurrence`'))
->groupBy('tag_id', 'content')
->orderBy('occurrence', 'desc')
->take(15)
->paginate(request('per_page'));
如果没有分页,查询大约需要20秒才能加载。我不经常使用group by
和join
查询,但我的猜测是group by
要求很多时间。
我在Stackoverflow和谷歌上冲浪,但没有运气。有什么尝试的建议吗? index
会有很大差异吗?
答案 0 :(得分:1)
假设有表:posts,tags和post_tag。后者将post_id和tag_id字段声明为索引,将foreign_key指定为相关表。
定义模型关系:
在标签型号上:
public function posts()
{
return $this->belongsToMany(Post::class);
}
On Post model:
public function tags()
{
return $this->belongsToMany(Tag::class);
}
在控制器上:
$tags = \App\Tag::withCount('posts')->orderBy('posts_count', 'DESC')->paginate(10);
意识到标签的帖子数量确实存在。
Laravel doc上的相关主题:https://laravel.com/docs/5.5/eloquent-relationships#counting-related-models
答案 1 :(得分:0)
您没有发布样本数据,因此我无法进行任何测试。
这只是一个想法,所以如果它不起作用,我会删除答案。
我以为你可以尝试(并检查表演)从你的查询中改变(据我所知,阅读你的代码)
(更新:感谢RolandStarke增加了LIMIT条款)
SELECT A.TAG_ID, B.CONTENT, COUNT(*) AS OCCURRENCE
FROM POST_TAG A
INNER JOIN TAGS B ON A.TAG_ID= B.ID
GROUP BY A.TAG_ID, B.CONTENT
ORDER BY OCCURENCE DESC
LIMIT 15;
到这一个:
SELECT A.TAG_ID, B.CONTENT, OCCURRENCE
FROM (SELECT TAG_ID, COUNT(*) AS OCCURENCE
FROM POST_TAG
GROUP BY TAG_ID
ORDER BY OCCURRENCE DESC LIMIT 15) A
INNER JOIN TAGS B ON A.TAG_ID= B.ID
ORDER BY OCCURENCE DESC;
请告诉我