2017-06-08 151 views
0

这里是我的表结构:如何选择所有包含特定标签的帖子?

// 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  | 
+---------+--------+ 

好的,那我有两个标签(phphtml),我需要选择标有他们的所有帖子。我怎样才能做到这一点?

目前我使用REGEXP,只是选择什么,我想是这样的:

SELECT * FROM posts WHERE keywords REGEXP 'php|html'; 

看到了吗?我甚至不使用1 join。现在我的数据集已经长大了,我的查询需要一段时间才能执行。我想我必须使用像join这样的关系特性。不过,我不确定它会比我目前的查询更好。

无论如何,有谁知道,我怎么能更快地得到预期的结果?

+1

你应该正常化你的数据(关键字内容)在适当的相关表 – scaisEdge

+0

在posts表中应该有标签ID列,然后你可以从帖子表中选择。 – OsamaKhalid

+0

@scaisEdge你的意思是?如果你写了一个答案并解释你建议的数据库设计,那么我会很满意。 –

回答

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%的帖子满足条件,那么这可能会更好,因为原则上执行计划不需要包括对整个帖子表的扫描。

+0

你能告诉我你的第二个查询中有哪些GROUP BY?对我来说似乎没用。如果我删除它,会发生什么?注意到我在实际中使用了'='而不是'IN'。 –

+1

'group by'用于避免结果集中同一篇文章的重复。当一个帖子在数据透视表中有两个匹配的条目时(一个用于“html”和一个用于“php”),就会发生这种情况。当你不使用'in'时,只用'='比较一个值,当然不需要分组。但你在问题中的例子提到了两个标签。 – trincot

1

您已经有了一个具有多对多关系的规范化设计。在posts表中不需要关键字列,因为数据透视表已经建立了相同的关键字列。

你只需要正确地进行连接。试试这个:

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。

+0

谢谢.. upvote –

相关问题