首页 文章

标签或标记的推荐SQL数据库设计[关闭]

提问于
浏览
256

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

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

6 回答

  • 8

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

    拥有“标签”表和 Map 表使得生成标签 Cloud 变得非常简单,因为您可以轻松地将SQL组合在一起以获取标签列表,其中包含每个标签使用频率的计数 .

  • 0

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

    Table: Item
    Columns: ItemID, Title, Content
    
    Table: Tag
    Columns: TagID, Title
    
    Table: ItemTag
    Columns: ItemID, TagID
    
  • 11

    我建议遵循以下设计:项目表:Itemid,taglist1,taglist2
    这将是快速的,可以轻松保存和检索项目级别的数据 .

    并行构建另一个表:Tags标签不会生成标签唯一标识符,如果第二列中的空间用完,则包含100个项目创建另一行 .

    现在,在搜索标签的项目时,它将非常快 .

  • 367

    如果您使用的是支持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非常相似 .

  • 67

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

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

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

  • 37

    通常我会同意Yaakov Ellis,但在这个特例中还有另一个可行的解决方案:

    使用两个表:

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

    这有一些主要优点:

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

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

    All Tags for one 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
    

    Tag-Cloud:

    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
    

    Items for one Tag:

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

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

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

相关问题