标签或标签的推荐SQL数据库设计

我听说过一些实现标签的方法;使用TagID和ItemID之间的映射表(对我来说有意义,但它是否缩放?),向ItemID添加固定数量的可能的TagID列(似乎是个坏主意),在文本列中保留逗号分隔的标签(听起来很疯狂,但可以工作)。我甚至听说有人建议使用稀疏矩阵,但是标签名如何优雅地增长呢?

我是否错过了标签的最佳实践?

125709 次浏览

三个表(一个用于存储所有项,一个用于存储所有标记,一个用于存储两者之间的关系),在适当的数据库上正确地建立索引,并设置外键,应该能够正常工作并适当地扩展。

Table: Item
Columns: ItemID, Title, Content


Table: Tag
Columns: TagID, Title


Table: ItemTag
Columns: ItemID, TagID

我总是把标签放在一个单独的表中,然后有一个映射表。当然,我也从来没有做过真正大规模的事情。

拥有一个“标签”表和一个映射表使得生成标签云变得非常简单。这样,因为您可以轻松地将SQL组合在一起,以获得包含每个标记使用频率计数的标记列表。

使用单个格式化文本列[1]存储标记,并使用功能强大的全文搜索引擎对其进行索引。否则,在尝试实现布尔查询时,您将遇到伸缩性问题。

如果需要关于所拥有的标记的详细信息,可以在增量维护的表中跟踪它,或者运行批处理作业来提取信息。

一些RDBMS甚至提供了原生数组类型,这种类型可能更适合存储,因为不需要解析步骤,但可能会导致全文搜索出现问题。

如果您正在使用支持map-reduce的数据库,如couchdb,那么将标记存储在纯文本字段或列表字段中确实是最好的方法。例子:

tagcloud: {
map: function(doc){
for(tag in doc.tags){
emit(doc.tags[tag],1)
}
}
reduce: function(keys,values){
return values.length
}
}

使用group=true运行该命令将根据标记名称对结果进行分组,甚至返回遇到该标记的次数的计数。它非常类似于计算一个单词在文本中的出现次数

通常情况下,我会同意Yaakov Ellis的观点,但在这种特殊情况下,还有另一种可行的解决方案:

使用两个表:

Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID


Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title

这有一些主要的优势:

首先,它使开发变得简单得多:在插入和更新item的三表解决方案中,你必须查找Tag表,看看是否已经有条目。然后你必须加入新的。这不是一项简单的任务。

然后,它使查询更简单(也许更快)。有三个主要的数据库查询,你将做:输出所有Tags为一个Item,绘制标签云和选择所有项目为一个标签标题。

一个项目的所有标签:

3表:

SELECT Tag.Title
FROM Tag
JOIN ItemTag ON Tag.TagID = ItemTag.TagID
WHERE ItemTag.ItemID = :id

2的表格:

SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id

类似于:

3表:

SELECT Tag.Title, count(*)
FROM Tag
JOIN ItemTag ON Tag.TagID = ItemTag.TagID
GROUP BY Tag.Title

2的表格:

SELECT Tag.Title, count(*)
FROM Tag
GROUP BY Tag.Title

一件物品

3表:

SELECT Item.*
FROM Item
JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
JOIN Tag ON ItemTag.TagID = Tag.TagID
WHERE Tag.Title = :title

2的表格:

SELECT Item.*
FROM Item
JOIN Tag ON Item.ItemID = Tag.ItemID
WHERE Tag.Title = :title

但是也有一些缺点:它可能会占用数据库中的更多空间(这可能会导致更慢的更多磁盘操作),并且它不是标准化的,这可能会导致不一致。

大小的争论并不是那么有力,因为标签的本质是它们通常非常小,所以大小的增加不是很大。有人可能会说,在一个只包含每个标签一次的小表中,对标签标题的查询要快得多,这当然是真的。但考虑到不必加入所节省的成本,以及可以在它们之上构建良好的索引,可以很容易地弥补这一点。当然,这在很大程度上取决于您所使用的数据库的大小。

前后矛盾的论点也有点毫无意义。标签是自由文本字段,没有像“将所有标签“foo”重命名为“bar”这样的操作。

tldr:我会选择双表解决方案。(事实上,我正要去。我找到了这篇文章,看看是否有有效的理由反对它。)

我建议以下设计: 项目表: Itemid, taglist1, taglist2
这将是快速和容易的保存和检索数据的项目级别。< / p > 并行构建另一个表: 标签 标签 不要让标签唯一的标识符,如果你用完了第二列的空间,其中包含100个项目,创建另一行。< / p >

现在,当搜索项目的标签,这将是超级快。