代码之家  ›  专栏  ›  技术社区  ›  bobobobo

实现标签的方法-每种方法的优缺点

  •  24
  • bobobobo  · 技术社区  · 16 年前

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

    方式二:“轻微规范化”(单独表格,无交叉点)

    table posts
    +--------+-------------------+
    | postId | title             |
    +--------+-------------------+
    |   1    | How do u tag?     |
    
    table taggings
    +--------+---------+
    | postId | tagName |
    +--------+---------+
    |   1    | C++     |
    |   1    | search  |
    

    赞成的意见 count(*) from taggings where tagName='C++' ).

    欺骗 :标记名可能会重复很多次。

    方法三:酷小子(用交集表规范化)

    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 回复  |  直到 6 年前
        1
  •  27
  •   Quassnoi    8 年前

    这些解决方案称为 mysqlicious , scuttle toxi .

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

        2
  •  1
  •   Thomas    16 年前

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

    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表中的名称。如果更改标记名的情况很少发生,那么这应该不是问题。如果更改标记名很常见,那么我将使用第三种解决方案,其中使用代理键引用标记。

        3
  •  0
  •   nico    16 年前

    我不同意解决方案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。。。既不是鱼也不是鸟

        4
  •  0
  •   Juha Syrjälä    16 年前

        5
  •  0
  •   urobo    15 年前

    嗯,我有同样的怀疑,我采用了我的网站的第三个解决方案。我知道还有另一种方法来处理可变长度元组的问题,即使用列作为行,这样您将获得一些识别元组冗余的信息,以及为每行组织的不同元组的信息。

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

    这确实很糟糕,但有时它是唯一可行的解决方案,而且它与关系方法相差甚远。