'简单'的mysql查询需要30秒才能加载

时间:2017-09-20 14:24:37

标签: php mysql laravel laravel-5

我正在使用Laravel Eloquent模型创建一个非常基本的MySQL查询。我有三个数据库表:poststagspost_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 byjoin查询,但我的猜测是group by要求很多时间。

我在Stackoverflow和谷歌上冲浪,但没有运气。有什么尝试的建议吗? index会有很大差异吗?

2 个答案:

答案 0 :(得分:1)

恕我直言,最好在创建相应的表,索引和外键后定义模型关系,并利用Laravel Eloquent来完成这项工作。 我几乎从不在我的任何Laravel项目中使用查询构建器来创建查询,而我正如我所说的那样,花费时间和精力来设计数据库表和相应的模型及其关系,这证明我最终会得到更清晰的代码表现更好。再次,这只是我个人的观点。 话虽如此,我正在展示一段产生你想要的结果的代码:

假设有表: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;

请告诉我