这是我的表结构:
// 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
这样的关系功能。但是我不确定它会比我当前的查询更好。
无论如何,有谁知道,我怎样才能更快地得到预期的结果?
答案 0 :(得分:1)
正则表达式的处理速度很慢。使用LIKE
可能会提供更好的响应时间:
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%的帖子满足条件,那么这可能会表现得更好,因为原则上执行计划不需要包括对整个帖子表的扫描。
答案 1 :(得分:1)
您已经拥有一个具有多对多关系的规范化设计。在posts表中没有必要使用keywords列,因为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。