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';
看到了吗?我甚至不使用1
join
。现在我的数据集已经成熟,我的查询需要一段时间才能执行。我想我必须使用关系特性,比如
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”)时,就会发生这种情况。当您在
中不使用
,并且只将
=
与一个值进行比较时,当然不需要分组。但是你在问题中的例子提到了两个标签。