【问题标题】:Multivalued attributes in Relational databases?关系数据库中的多值属性?
【发布时间】:2011-11-22 12:35:36
【问题描述】:

当一个想法被广泛引用时,它们在关系数据库中的多值属性有多好?

让我举个例子来说明我的意思。假设我有下表:

UserID          Attribute1

User1           a,b,c
User2           x,y,z
User3           a,x,y
User4           c,b,z
[a,b,c,x,y,z are to be strings]

还有另一个用户User5,我必须根据他的Attribute1 是否与其他4 个用户中的任何一个匹配,向他提出一些关于其他用户的建议。

[在图形数据库中,任务可能会容易得多,因为我可以使用相同的关系从各个用户创建多个节点。]

现在,该表只是对实际数据库外观的微观抽象。表中的行数可能会达到数十万,如果不是数百万的话。此外,多个值实际上可能远远超过 3。除此之外,数据库可能处于高负载状态,在这种情况下,可能会出现一些问题。

那么,多值属性在这种情况下有用吗?或者有没有更好的方法来做同样的事情?我能想到的一种明显方法是将其存储为:

UserID          Attribute1

User1           a
User1           b
User1           c
User2           x
User2           y
User2           z
User3           a
User3           x
User3           y
User4           c
User4           b
User4           z

在数据库中处理这种情况的任何更快的方法?或者是否有任何现代数据库的内置功能可供利用?

【问题讨论】:

  • 我的直觉是,关系数据库的关系部分比字符串匹配部分优化得多:-) 数据库几乎总是工作得最好,并且在最标准化的形式下最容易优化,这将是后一种选择(所有属性分散到多行中)。
  • 报告数据库通常在经过深思熟虑的非规范化后表现更好..
  • @mellamokb:“数据库几乎总是在最规范化的形式下工作得最好,并且最容易优化”——不正确:最高规范形式是 6NF 可能会导致“爆炸”表,需要许多连接来编写最简单的查询,并强制使用触发器或其他过程代码来强制执行表间约束,这两种方法都不利于优化。另请注意,如果 5NF 设计没有冗余,则可能没有什么实际理由将其采用 6NF 来消除某些重要的依赖关系。

标签: sql database database-design relational-database


【解决方案1】:

只有当数据在数据库中是死重时,一个字段中的多个值才有用,即,如果您只从数据库中读取该字段并在之后进行处理。

只要您想在查询中使用字段中的值,您就会因为必须解析值来比较它而遭受巨大的性能损失。如果您像第二个示例那样将值放在单独的记录中,以便在其上添加索引,那么查询速度将提高 10000 倍并非不现实。

在表中拥有一百万条记录不是问题。我们有一些表,其中包含超过 1 亿条记录。

【讨论】:

    【解决方案2】:

    除了其他人对规范化的看法之外,我想回答您问题的“或现代数据库的任何内置功能?”部分问题:

    PostgreSQL 有一个非常漂亮的扩展名为hstore,它以高度优化的方式做到了这一点。

    hstore 数据类型本质上是一个键/值对,您可以在其中存储任何内容。在你的例子中是这样的:

    INSERT INTO user_attributes
    (user_id, , attributes)
    VALUES
    (1, ('att1 => x, att2 => y'));
    

    将键 att1att2 插入到列属性中。这可以被索引以快速查找。

    您可以使用以下语法查询数据:

    SELECT *
    FROM user_attributes
    WHERE attributes @> ('att1 => "Some Value"')
    

    这将返回所有具有名为att1 的键并且映射到值“Some Value”的行。上面的语句将使用列上的现有索引,因此查找几乎与使用“真实”列一样快。上面的语句在我的笔记本电脑上需要大约 2 毫秒才能在有 100.000 行的表中找到一行。

    您还可以查询定义了特定属性而不考虑值的行:

    SELECT user_id,
           (attributes -> 'att1')
    FROM user_attributes
    WHERE attributes ? 'att1'
    

    将查找定义了att1 的所有行,并将输出这些行的值。

    【讨论】:

      【解决方案3】:

      对于 nn 表,您可以将其规范化为 3 个表(在事务模型中)用户 - user_attribute - 属性,其中 user_attribute 表由用户和属性的主键组成。键通常被索引,因此对于读取操作

      问题后编辑

      Users
      int Id PrimaryKey
      string name
      

      User_Attribute
      UserId PrimaryKey (FK to Users.Id)
      AttributeId PrimaryKey (FK to Attributes.Id)
      

      Attributes
      int Id PrimaryKey
      Value
      

      这将导致一个只包含用户的表,一个只包含属性的表和一个包含哪个用户持有什么的表

      例如

         Users      User_Attribute      Attrubutes      
      id  Name   UserId AttributeId  Id Value
      1   User1  1      1            1  Att1
      2   User2  1      2            2  Att2
                 2      1            3  Att3  
                 2      3
      

      【讨论】:

      • 我听不懂你的意思...你能说清楚点吗?我的意思是你能参考上面的例子解释一下吗?
      • 好的……那么在这种情况下,非规范化是要走的路吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-26
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      • 2013-02-02
      • 2023-03-21
      • 1970-01-01
      相关资源
      最近更新 更多