推荐用于标记或标记的SQL数据库设计

时间:2008-08-21 19:18:06

标签: sql database-design tags data-modeling tagging

我听说过几种实现标记的方法;使用TagID和ItemID之间的映射表(对我来说有意义,但它是否可以扩展?),向ItemID添加固定数量的可能TagID列(看起来是个坏主意),将标记保留在逗号分隔的文本列中(声音疯了,但可以工作)。我甚至听过有人推荐稀疏矩阵,但那么标签名称如何优雅地增长?

我错过了标签的最佳做法吗?

6 个答案:

答案 0 :(得分:379)

三个表(一个用于存储所有项目,一个用于所有标记,一个用于两者之间的关系),正确编制索引,外键设置在适当的数据库上运行,应该可以正常工作并正确缩放。

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID

答案 1 :(得分:71)

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

使用两个表:

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

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

这有一些主要优点:

首先,它使开发变得更加简单:在用于插入和更新item的三表解决方案中,您必须查找Tag表以查看是否已有条目。然后你必须加入新的。这不是一件轻而易举的事。

然后它使查询更简单(也许更快)。您将执行三种主要的数据库查询:为一个Tags输出所有Item,绘制一个Tag-Cloud并选择一个标记标题的所有项目。

一个项目的所有标记:

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

但是也有一些缺点:它可能需要在数据库中占用更多空间(这可能导致更多的磁盘操作更慢)并且没有规范化可能导致不一致。

size参数不是那么强大,因为标签的本质是它们通常非常小,所以尺寸增加不是很大。有人可能会争辩说,标签标题的查询在一个只包含每个标签一次的小表中要快得多,这肯定是正确的。但是考虑到不必加入的节省以及你可以为它们建立一个好的索引的事实可以很容易地弥补这一点。这当然在很大程度上取决于您使用的数据库的大小。

不一致论点也有点没有实际意义。标签是自由文本字段,没有预期的操作,如'重命名所有标签'foo“到”bar“'。

所以tldr:我会选择双桌解决方案。 (事实上​​我要去。我发现这篇文章是否有反对它的有效论据。)

答案 2 :(得分:37)

如果您正在使用支持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运行此命令会按标记名称对结果进行分组,甚至返回遇到标记的次数计数。它与counting the occurrences of a word in text非常相似。

答案 3 :(得分:12)

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

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

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

答案 4 :(得分:8)

我总是将标签保存在一个单独的表中,然后有一个映射表。当然,我从未做过大规模的任何事情。

拥有“标签”表和地图表可以轻松生成标签云&因为您可以轻松地将SQL组合在一起以获取标记列表,其中包含每个标记使用频率的计数。

答案 5 :(得分:0)

我建议遵循以下设计: 项目表: Itemid,taglist1,taglist2
这将很快并且可以轻松保存并在项目级别检索数据。

并行构建另一个表: 标签 标签 不要创建标记唯一标识符,如果第二列中包含的空间不足,则说100个项目创建另一行。

现在,在搜索标签的项目时,它会非常快。