Mysql 如何选择所有具有特定标签的帖子?
以下是我的表格结构:Mysql 如何选择所有具有特定标签的帖子?,mysql,sql,join,Mysql,Sql,Join,以下是我的表格结构: // posts +----+-----------+---------------------+-------------+ | id | title | body | keywords | +----+-----------+---------------------+-------------+ | 1 | title1 | Something here | php,oop | | 2 | tit
// posts
+----+-----------+---------------------+-------------+
| id | title | body | keywords |
+----+-----------+---------------------+-------------+
| 1 | title1 | Something here | php,oop |
| 2 | title2 | Something else | html,css,js |
+----+-----------+---------------------+-------------+
// tags
+----+----------+
| id | name |
+----+----------+
| 1 | php |
| 2 | oop |
| 3 | html |
| 4 | css |
| 5 | js |
+----+----------+
// pivot
+---------+--------+
| post_id | tag_id |
+---------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
| 2 | 5 |
+---------+--------+
好的,我有两个标签(
php
和html
),我需要选择所有贴有标签的帖子。我该怎么做
目前我使用的是REGEXP
,只需像这样选择我想要的:
SELECT * FROM posts WHERE keywords REGEXP 'php|html';
看到了吗?我甚至不使用1join
。现在我的数据集已经成熟,我的查询需要一段时间才能执行。我想我必须使用关系特性,比如join
。但是,我不确定它是否会比我当前的查询更好
不管怎样,有人知道吗,我怎样才能更快地得到预期的结果呢?正则表达式处理起来可能很慢。像一样使用
可能会提供更好的响应时间:
SELECT *
FROM posts
WHERE (keywords LIKE '%php%' OR keywords LIKE '%html%')
基于标准化表的查询将是:
SELECT posts.id, posts.title, posts.body, posts.keywords
FROM posts
INNER JOIN pivot ON pivot.post_id = posts.id
INNER JOIN tags ON tags.id = pivot.tag_id
WHERE tags.name IN ('html', 'php')
GROUP BY posts.id
为了获得最佳速度,您必须确保id
字段声明为主键,并且在以下各项上具有索引:
tags(name)
pivot(tag_id)
尽管如此,如果所有帖子中有很大一部分符合条件,那么这不会比您当前的解决方案更快:它很可能会更慢。但是,例如,如果不到1%的POST能够满足该条件,那么这可能会表现得更好,因为原则上执行计划不需要包括对整个POST表的扫描。正则表达式的处理速度可能较慢。像
一样使用可能会提供更好的响应时间:
SELECT *
FROM posts
WHERE (keywords LIKE '%php%' OR keywords LIKE '%html%')
基于标准化表的查询将是:
SELECT posts.id, posts.title, posts.body, posts.keywords
FROM posts
INNER JOIN pivot ON pivot.post_id = posts.id
INNER JOIN tags ON tags.id = pivot.tag_id
WHERE tags.name IN ('html', 'php')
GROUP BY posts.id
为了获得最佳速度,您必须确保id
字段声明为主键,并且在以下各项上具有索引:
tags(name)
pivot(tag_id)
尽管如此,如果所有帖子中有很大一部分符合条件,那么这不会比您当前的解决方案更快:它很可能会更慢。但是,例如,如果只有不到1%的POST能够满足条件,那么这可能会表现得更好,因为原则上执行计划不需要包括对整个POST表的扫描。您已经有了一个具有多对多关系的规范化设计。posts表中不需要有关键字列,因为pivot已经建立了相同的关键字列
您只需要正确地进行连接。试试这个:
SELECT posts.id
FROM posts
LEFT OUTER JOIN pivot
ON posts.id = pivot.post_id
LEFT OUTER JOIN tags
ON pivot.tag_id = tags.id
WHERE tags.name = "php" or tags.name = "html"
GROUP BY posts.id;
这将为您提供带有标签的帖子的所有id。您已经有了一个具有多对多关系的规范化设计。posts表中不需要有关键字列,因为pivot已经建立了相同的关键字列
您只需要正确地进行连接。试试这个:
SELECT posts.id
FROM posts
LEFT OUTER JOIN pivot
ON posts.id = pivot.post_id
LEFT OUTER JOIN tags
ON pivot.tag_id = tags.id
WHERE tags.name = "php" or tags.name = "html"
GROUP BY posts.id;
这将为您提供带有标记的帖子的所有id。您应该在适当的相关表格中规范化数据(关键字内容)。在帖子表格中应该有带有标记id的列,然后您可以从帖子表格中进行选择。@scaisEdge您的确切意思是什么?如果你写一个答案并解释你建议的数据库设计,我会很激动的。@MartinAJ你可以用like。where(关键字,如“%php%”或关键字,如“%html%”)。您应该在适当的相关表格中规范化数据(关键字内容)。在posts表格中,应该有带有标记ID的列,然后您可以从posts表格中选择。@scaisEdge您的确切意思是什么?如果你写一个答案并解释你建议的数据库设计,我会很激动的。@MartinAJ你可以用like。where(像“%php%”这样的关键字或像“%html%”这样的关键字)。您能告诉我在第二次查询中,groupby
做了什么吗?对我来说似乎没用。如果我移除它会发生什么?注意,我在
中使用了=
而不是实际中的。group by
用于避免在结果集中重复相同的帖子。当一篇文章在pivot表中有两个匹配的条目(一个用于“html”,一个用于“php”)时,就会发生这种情况。当您在
中不使用,并且只将=
与一个值进行比较时,当然不需要分组。但是你在问题中的例子提到了两个标签。你能告诉我在你的第二个查询中,groupby
做了什么吗?对我来说似乎没用。如果我移除它会发生什么?注意,我在
中使用了=
而不是实际中的。group by
用于避免在结果集中重复相同的帖子。当一篇文章在pivot表中有两个匹配的条目(一个用于“html”,一个用于“php”)时,就会发生这种情况。当您在
中不使用,并且只将=
与一个值进行比较时,当然不需要分组。但是你在问题中的例子提到了两个标签。