实现标签的方法 - 各自的优点和缺点

时间:2010-05-21 21:03:08

标签: sql tags

Related

使用SO作为示例,如果您预计标签会经常更改,那么管理标签的最明智方法是什么?

方式1:严重非规范化(以逗号分隔)

table posts
+--------+-----------------+ 
| postId | tags            |
+--------+-----------------+
|   1    | c++,search,code |

此处标记以逗号分隔。

优点:使用单个select查询一次检索标记。更新标签很简单。 更新简单且便宜。

缺点:对标签检索进行额外解析,很难统计有多少帖子使用哪个标签。

(或者,如果仅限于5个标签)

table posts
+--------+-------+-------+-------+-------+-------+
| postId | tag_1 | tag_2 | tag_3 | tag_4 | tag_5 |
+--------+-------+-------+-------+-------+-------+
|   1    | c++   |search | code  |       |       | 

方式2:“稍微规范化”(单独的表,没有交叉点)

table posts
+--------+-------------------+
| postId | title             |
+--------+-------------------+
|   1    | How do u tag?     |

table taggings
+--------+---------+
| postId | tagName |
+--------+---------+
|   1    | C++     |
|   1    | search  |

优点:很容易看到代码计数(count(*) from taggings where tagName='C++')。

缺点:tagName可能会重复很多次。

方式3:酷孩子(用交叉表标准化)

table posts
+--------+---------------------------------------+
| postId | title                                 |
+--------+---------------------------------------+
|   1    | Why is a raven like a writing desk?   |

table tags
+--------+---------+
| tagId  | tagName |
+--------+---------+
|   1    | C++     |
|   2    | search  |
|   3    | foofle  |

table taggings
+--------+---------+
| postId | tagId   |
+--------+---------+
|   1    | 1       |
|   1    | 2       |
|   1    | 3       |

优点

  • 没有重复的标签名称。
  • 更多女孩会喜欢你。

缺点:更改标签的费用比#1更贵。

5 个答案:

答案 0 :(得分:25)

这些解决方案称为mysqliciousscuttletoxi

This article比较了每种方法的优点和缺点。

答案 1 :(得分:1)

我认为第四种解决方案是第三种解决方案的变体:

Create Table Posts
(
    id ...
    , title ...
)
Create Table Tags
(
    name varchar(30) not null primary key
    , ...
)

Create Table PostTags
(
    PostId ...
    , TagName varchar(30) not null
    , Constraint FK_PostTags_Posts
        Foreign Key ( PostId )
        References Posts( Id )
    , Constraint FK_PostTags_Tags
        Foreign Key ( TagName )
        References Tags( Name )
        On Update Cascade
        On Delete Cascade
)

请注意,我使用标记名称作为Tags表的主键。通过这种方式,您可以过滤某些标签,而无需额外连接到Tags表本身。此外,如果更改标记名称,它将更新PostTags表中的名称。如果更改标签名称很少发生,那么这应该不是问题。如果更改标签名称是常见的情况,那么我将使用您的第三个解决方案,您可以使用代理键来引用标签。

答案 2 :(得分:0)

我个人赞成解决方案#3。

我不同意解决方案#1更容易保留。 想想你必须改变标签名称的情况。

解决方案#1:

UPDATE posts SET tag = REPLACE(tag, "oldname", "newname") WHERE tag LIKE("%oldname%")

解决方案#3:

UPDATE tags SET tag = "newname" WHERE tag = "oldname" 

第一个更重。

此外,删除标签时你必须处理逗号(好的,它很容易完成,但仍然,更难以删除taggings表中的一行)

至于解决方案#2 ......既不是鱼也不是鸡?

答案 3 :(得分:0)

我认为SO使用解决方案#1。我会选择#1或#3。

要考虑的一件事是,如果您有几件可以标记的东西(例如,为帖子和产品添加标签)。这可能会影响数据库解决方案。

答案 4 :(得分:0)

我有同样的疑问,我为我的网站采用了第三种解决方案。我知道还有另一种处理变长元组问题的方法,其中包括使用列作为行,这样你就可以获得一些信息来识别元组减少量,而变量元素则为每行组织一个。

+--------+-------+-------------------------------------+
| postId | label | value                               | 
+--------+-------+-------------------------------------+
|   1    | tag   |C++                                  |
+--------+-------+-------------------------------------+
|   1    | tag   |search                               | 
+--------+-------+-------------------------------------+
|   1    | tag   |code                                 |
+--------+-------+-------------------------------------+
|   1    | title | Why is a raven like a writing desk? |
+--------+-------+-------------------------------------+ 

这真的很糟糕,但有时它是唯一可行的解​​决方案,而且距离关系方法还很远。