推荐用于标记或标记的 SQL 数据库设计 [关闭]
-
09-06-2019 - |
题
我听说过几种实现标记的方法;在 TagID 和 ItemID 之间使用映射表(对我来说有意义,但它可以扩展吗?),向 ItemID 添加固定数量的可能 TagID 列(似乎是个坏主意),将标签保留在以逗号分隔的文本列中(听起来疯狂但可以工作)。我什至听说有人推荐稀疏矩阵,但是标签名称如何优雅地增长呢?
我是否缺少标签的最佳实践?
解决方案
三个表(一个用于存储所有项目,一个用于所有标签,一个用于两者之间的关系),正确索引,并在适当的数据库上运行外键集,应该可以正常工作并适当扩展。
Table: Item
Columns: ItemID, Title, Content
Table: Tag
Columns: TagID, Title
Table: ItemTag
Columns: ItemID, TagID
其他提示
通常我会同意 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:我会选择两张桌子的解决方案。(事实上我正要去。我找到这篇文章是为了看看是否有有效的论据反对它。)
如果您使用支持 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 运行此命令将按标签名称对结果进行分组,甚至返回遇到该标签的次数。它非常类似于 计算文本中某个单词的出现次数.
使用单个格式化文本列[1]来存储标签,并使用功能强大的全文搜索引擎对其进行索引。否则,在尝试实现布尔查询时,您将遇到扩展问题。
如果您需要有关所拥有标签的详细信息,您可以在增量维护的表中跟踪它,或者运行批处理作业来提取信息。
[1] 一些 RDBMS 甚至提供原生数组类型,由于不需要解析步骤,该类型可能更适合存储,但可能会导致全文搜索出现问题。
我总是将标签保存在单独的表中,然后有一个映射表。当然,我也从未做过大规模的事情。
拥有“标签”表和映射表使得生成标签云变得非常简单,因为您可以轻松地将 SQL 放在一起来获取标签列表,并计算每个标签的使用频率。
我建议以下设计:项目表:项目ID、标签列表1、标签列表2
这将是快速的,并且可以轻松地保存和检索项目级别的数据。
并行构建另一个表:标签标签不会使标签唯一标识符,如果您在第二列中用完了空间,其中包含100个项目创建另一行。
现在,在搜索标签项目时,速度会非常快。