Php ';简单';mysql查询需要30秒才能加载
我正在使用Laravel雄辩的模型创建一个非常基本的MySQL查询。我有三个数据库表:Php ';简单';mysql查询需要30秒才能加载,php,mysql,laravel,laravel-5,Php,Mysql,Laravel,Laravel 5,我正在使用Laravel雄辩的模型创建一个非常基本的MySQL查询。我有三个数据库表:posts、tags和post\u tag(透视表)。我想得到和分页最常用的标签。查询正在运行,但加载大约需要30秒。tags表有约9k条记录,post\u tag表有约26k条记录。但在不久的将来,他们的post_标签表中的记录将超过100万条 代码如下: $tags = Tag::leftJoin('post_tag', 'tags.id', '=', 'post_tag.tag_id') ->
posts
、tags
和post\u tag
(透视表)。我想得到和分页最常用的标签。查询正在运行,但加载大约需要30秒。tags
表有约9k条记录,post\u tag
表有约26k条记录。但在不久的将来,他们的post_标签
表中的记录将超过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秒。我不经常使用groupby
和join
查询,但我猜groupby
需要很多时间
我在Stackoverflow和Google上冲浪,但没有任何运气。有什么建议吗?
索引
会有很大区别吗?您没有发布样本数据,因此我无法进行任何测试
这只是一个想法,所以如果它不起作用,我会删除答案
我在想,您可以尝试(并检查性能)改变您的查询(据我所知,阅读您的代码)
(更新:感谢罗兰·斯塔克增加了限制条款)
对于这一点:
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;
请让我知道IMHO,最好在创建相应的表、索引和外键后定义模型关系,并利用Laravel Elount来完成这项工作。 我几乎从来没有在我的Laravel项目中使用query builder来创建查询,相反,正如我所说,我花时间和精力来设计数据库表和相应的模型以及它们之间的关系,这向我证明,最终得到的代码更干净,性能更好。同样,这只是我个人的观点。 话虽如此,我展示了一段代码,它产生了您想要的结果: 假设有表:posts、tag和post_tag。后者将post_id和tag_id字段声明为索引,并将外键指向它们的相关表 定义模型关系: 标签型号:
public function posts()
{
return $this->belongsToMany(Post::class);
}
关于Post模型:
public function tags()
{
return $this->belongsToMany(Tag::class);
}
在控制器上:
$tags = \App\Tag::withCount('posts')->orderBy('posts_count', 'DESC')->paginate(10);
要意识到一个标签所拥有的帖子数量实际上就是它的出现
Laravel文档的相关主题:为什么要同时按标记id和内容进行分组?否则mysql抛出错误:
1055 Expression\35; SELECT list的2不在GROUP by子句中,并且包含未聚合的列
Yes,列上的索引可能会减少运行时间,也会减少您分组的列数。将索引添加到tag\u id
和content
可以显著缩短执行时间。现在需要450毫秒。@RolandStarke谢谢。。。更新后的answerI'v以前从未使用with count()
方法。非常有用,每天学点东西:-)。干杯
$tags = \App\Tag::withCount('posts')->orderBy('posts_count', 'DESC')->paginate(10);