如何在数据库中存储具有动态数量的属性的数据

时间:2009-09-18 13:09:35

标签: mysql database rdbms

我有许多具有不同数量属性的不同对象。到目前为止,我已将数据保存在XML文件中,这些文件可轻松实现不断变化的属性数量。但我正试图将其移至数据库。

存储此数据的首选方式是什么?

到目前为止我已经确定了一些策略:

  • 在对象的表中有一个名为“attributes”的字段,并将数据序列化或json存储在那里。
  • 将数据存储在两个表(对象,属性)中,并使用第三个来保存关系,使其成为真正的n:m关系。非常干净的解决方案,但获取整个对象及其所有属性可能非常昂贵
  • 识别所有对象共有的属性,并为对象的表创建这些属性。将其余属性作为序列化数据存储在另一个字段中。这比第一个策略更有优势,使搜索更容易。

有什么想法吗?

8 个答案:

答案 0 :(得分:22)

如果您计划搜索特定属性,那么将它们序列化为单个列是一个坏主意,因为您必须使用每行函数来获取信息 - 这很少能很好地扩展。

我会选择你的第二选择。拥有属性表中的属性列表,自己表中的对象以及称为对象属性的多对多关系表。

例如:

objects:
    object_id    integer
    object_name  varchar(20)
    primary key  (object_id)
attributes:
    attr_id      integer
    attr_name    varchar(20)
    primary key  (attr_id)
object_attributes:
    object_id    integer  references (objects.object_id)
    attr_id      integer  references (attributes.attr_id)
    oa_value     varchar(20)
    primary key (object_id,attr_id)

您注意到对性能的关注,但根据我的经验,拆分列的成本总是比组合多列更昂贵。如果事实证明存在性能问题,那么出于性能原因打破3NF是完全可以接受的。

在这种情况下,我会以相同的方式存储它,但也有一个包含原始序列化数据的列。如果使用插入/更新触发器来保持列式和组合数据同步,则不会出现任何问题。但是,在实际出现问题之前,你不应该担心这一点。

通过使用这些触发器,您可以最大限度地减少数据更改时 所需的工作量。通过尝试提取子列信息,您可以对每个选择进行不必要的工作。

答案 1 :(得分:6)

2d解决方案的变体只是两个表(假设所有属性都是单一类型):

T1:|对象数据列| Object_id |

T2:| Object id | attribute_name | attribute value | (前2列的唯一索引)

与第3种解决方案结合使用时效率更高,例如所有常见字段都进入T1。

不建议将Sstuffing> 1属性放入同一个blob中 - 您无法按属性过滤,无法有效更新它们

答案 2 :(得分:3)

让我对DVK所说的内容给出一些具体的解释。

假设值的类型相同,表格看起来就像(祝你好运,我觉得你需要它):

dynamic_attribute_table
------------------------
id         NUMBER
key        VARCHAR
value      SOMETYPE?

示例(汽车):

|id|    key   |   value   |
---------------------------
| 1|'Make'    |'Ford'     |
| 1|'Model'   |'Edge'     |
| 1|'Color'   |'Blue'     |
| 2|'Make'    |'Chevrolet'|
| 2|'Model'   |'Malibu'   |
| 2|'MaxSpeed'|'110mph'   |

因此,
实体1 = {('Make','Ford'),('Model','Edge'),('Color','Blue')}
并且,
实体2 = {('Make','Chevrolet'),('Model','Malibu'),('MaxSpeed','110mph')}。

答案 3 :(得分:2)

如果您使用的是关系数据库,那么我认为您在列出选项方面做得很好。他们各有利弊。你最有能力决定什么最适合你的情况。

序列化方法可能是最快的(取决于您的反序列化代码),但这意味着您将无法使用SQL查询数据。如果你说你不需要用SQL查询数据,那么我同意@longneck,也许你应该使用键/值样式db而不是关系数据库。

编辑 - 阅读更多评论,如果速度是您的主要考虑因素,您为什么要切换到数据库。关于您当前的XML实现有什么不好?

答案 4 :(得分:2)

我曾经实施this scheme

t_class (id RAW(16), parent RAW(16)) -- holds class hierachy.
t_property (class RAW(16), property VARCHAR) -- holds class members.
t_declaration (id RAW(16), class RAW(16)) -- hold GUIDs and types of all class instances
t_instance (id RAW(16), class RAW(16), property VARCHAR2(100), textvalue VARCHAR2(200), intvalue INT, doublevalue DOUBLE, datevalue DATE) -- holds 'common' properties

t_class1 (id RAW(16), amount DOUBLE, source RAW(16), destination RAW(16)) -- holds 'fast' properties for class1.
t_class2 (id RAW(16), comment VARCHAR2(200)) -- holds 'fast' properties for class2
--- etc.

RAW(16)Oracle拥有GUID s

的地方

如果要选择对象的所有属性,请发出:

SELECT  i.*
FROM    (
        SELECT  id 
        FROM    t_class
        START WITH
                id = (SELECT class FROM t_declaration WHERE id = :object_id)
        CONNECT BY
                parent = PRIOR id
        ) c
JOIN    property p
ON      p.class = c.id
LEFT JOIN
        t_instance i
ON      i.id = :object_id
        AND i.class = p.class
        AND i.property = p.property

t_property保存您通常不会搜索的内容(例如,文字说明等)。

快速属性实际上是数据库中的普通表,以提高查询效率。它们仅为某个类或其后代的实例保存值。这是为了避免额外的连接。

您不必使用快速表并将所有数据限制在这四个表中。

答案 5 :(得分:1)

听起来你需要点击couchdb,而不是RDBMS。

答案 6 :(得分:1)

如果您要在稍后的时间点编辑/操作/删除属性,那么制作一个真正的n:m(第二个选项)就是我要去的那个。 (或者尝试将其设为2表,其中相同的属性重复。但数据大小会很高)

如果您没有处理属性(只捕获和显示数据),那么您可以继续使用一些分隔符存储在一个字段中(确保分隔符不会出现在属性值中)

答案 7 :(得分:0)

我假设您没有数字属性汤,但是您的数据有一定顺序。

否则,RDBMS可能不是最合适的。没有SQL的地方可能会更好。

如果您的对象属于不同类型,则通常每种类型应有一个表。

特别是如果要使用主键进行连接。如果您具有“产品”,“订单”,“客户”等表,而不仅仅是“对象和属性”表,则还有助于带来订单和理智。

然后查看您的属性。对于该类型类别中50%的对象,存在的所有内容都超过该对象,则将其设置为对象表中的一列,并在不使用时使用null

任何强制性的内容,当然都应定义为NOT NULL列。

其余的,您可以具有一个或几个“额外属性”表。

您可以将属性名称和值一起放入表中,或将它们规范化到单独的表中,而仅在值表中使用主键。

您可能还会发现您有数据组合。例如,一种对象类型的变体始终具有一组特定的属性,而同一对象类型的另一种变体具有另一组属性。

在这种情况下,您可能想要执行以下操作:

MainObjectTable:
  mainObjectId: PRIMARY KEY
  columns...
MainObjectVariant1Table:
  mainObjectId: FOREIGN KEY TO MainObjectTable
  variant1Columns...
MainObjectVariant2Table:
  mainObjectId: FOREIGN KEY TO MainObjectTable
  variant2Columns...

我认为,从长远来看,将获得回报的艰巨工作是分析数据,找到对象和常用属性,并使之成为一个好的“对象/ ERD / DB”模型。