在数据库中存储标记的最有效方法是什么?

我正在我的网站上实现一个类似于 stackoverflow 的标签系统,我的问题是-什么是最有效的方法来存储标签,以便它们可以被搜索和过滤?

我的想法是:

Table: Items
Columns: Item_ID, Title, Content


Table: Tags
Columns: Title, Item_ID

会不会太慢了? 有没有更好的办法?

118122 次浏览

你不能根据问题中提供的数据来讨论速度。我认为在这个开发阶段,您甚至不应该过分担心性能问题。叫做 过早优化

但是,我建议在 Tags 表中包含 Tag _ ID 列。每个表都有一个 ID 列通常是一个好的实践。

我建议使用中间的第三个表来存储标签 < = > 项目关联,因为我们在标签和项目之间有多对多的关系,即一个项目可以与多个标签关联,而一个标签可以与多个项目关联。 HTH, 阀门。

如果空间有问题,那么使用第三个表 Tags (Tag _ Id,Title)来存储标记的文本,然后将 Tags 表更改为(Tag _ Id,Item _ Id)。这两个值也应该提供唯一的组合主键。

一个项目将有许多标签。一个标签将属于多个项目。这意味着您很可能需要一个中间表来克服多对多的障碍。

比如:

表: 项目
列: Item _ ID,Item _ Title,Content

表: 标签
列: Tag _ ID,Tag _ Title

表: Items _ Tags
列: Item _ ID,Tag _ ID

也许你的 web 应用程序非常流行,需要在将来进行非常规化,但是过早搅浑水是没有意义的。

项目应该有一个“ ID”字段,标签应该有一个“ ID”字段(主键,聚集)。

然后创建一个 ItemID/TagID 中间表,并将“ 完美索引”放在上面。

实际上,我相信去规范化标签表可能是一个更好的方法,这取决于规模。

这样,标记表只有 tagid、 itemid 和 tagname。

您将得到重复的标签名,但是它使得为特定项目添加/删除/编辑标签变得更加简单。您不必创建新标记,删除旧标记的分配并重新分配新标记,只需编辑标记名即可。

对于显示标记列表,您只需使用 DISTINCT 或 GROUPBY,当然您也可以计算一个标记可以轻松使用多少次。

如果您不介意使用一些非标准的东西,Postgres 9.4及以上版本可以选择存储 JSON 文本数组类型的记录。

你的模式是:

Table: Items
Columns: Item_ID:int, Title:text, Content:text


Table: Tags
Columns: Item_ID:int, Tag_Title:text[]

欲了解更多信息,请看 Josh Berkus 的这篇精彩文章: Http://www.databasesoup.com/2015/01/tag-all-things.html

就性能而言,有更多不同的选项可供彻底比较,上面建议的选项总体上是最好的。

标记架构: 标记表和属性:

表:

tags (each row only keeps information about a particular tag)
taggings (each row keeps information about trigger and who will receive the trigger )
products_tags (each row keeps information about tag with particular product)
tag_status (each row keeps track of a tag status)

表: 标签标签的属性表:

id(PK)
userId(FK users)(not null)(A tag only belongs to one user, but  a user can create multiple tags. So it is one to many relationships.)
genreId(FK products_geners)(not null)
name (string) (not null)
description (string)
status (int) (0=inactive, 1=pending, 2=active, there could be more flag)
rank(int)  (rank is the popularity of a particular tag), this field can be use for sorting among similar tags.)
type (int) (0=type1, 1=type2, 2=type3)
photo(string)
visibility (int) (0=public, 2=protected, 3 = private)(private means the tag only  visible to assigned users of a product, protected means a tag only visible to all friends and followers of the creator of the tag, public means search by public, such as all admin created tag)
createdAt(timestamp for the tag was created at)
updatedAt (timestamp for the tag last time updated)
deletedAt (default value null) (timestamp when tag was deleted, we need this field because we will delete tag permanently from audit table).

注意: 保留10号字段将在以后派上用场。

表: 标签:

此表将用于触发,例如广播其他用户的提要或向他们发送通知。在此表中插入一行之后,将有一个服务读取一行,并采取相关联的操作删除该行。

标签属性表:

Id(PK)
tagId(a tagging row only belongs to a tag, but a tag can have multiple row).
taggableId (id of a user who will receive notification)
taggableType(int) (0=notification, 1=feed message)
taggerId(the person who triggered the broadcast)
taggerType(ad, product, news)
createdAt(timestamp for the tag was created at)

表: products _ tag

从用户的角度来看,用户可以在实例化一个产品后创建一个标签,因此下表将保存关于哪些产品具有哪些标签的信息。

标签属性表:

Id (PK)
productId(FK)
tagId(FK)

表: tag _ status

当用户创建一个标签时,在这个表中将创建一行 tagId 和默认状态为 inactive/ending 的标签,管理员将从标签表中提取所有标签,其中 status = ending/inactive,如果管理员批准了标签,那么在标签表中的 status 值将被批准,标签 _ status 行将被删除。如果 admin 被拒绝,那么 tag _ status 表的 status 字段的值将被拒绝,触发器将被广播,接收方将向相关用户发送一个通知,通知他的标记被拒绝。

id(PK)
senderId(Id of the user)
receiverId(Id of admin user)
createdAt(timestamp of created at)
updatedAt(timestamp of updated at)
deletedAt(timestamp of deletedAt) default value null
expiredAt (if a tag never gets approved it will expire after a certain time for removing its information from the database. If a rejected tag gets updated by user then expiredAt will reset to new future time)
status
Message (string varchar(256)) (message for user)