【问题标题】:What is the proper way to store 'metadata' in relational database?在关系数据库中存储“元数据”的正确方法是什么?
【发布时间】:2013-02-01 20:38:44
【问题描述】:

我有一个名为assets 的表,其中资产可以属于一个用户、团队或部门,并且可能属于每个用户、团队或部门的多个。我的问题是资产是高度可变的,并且可能具有与它们相关联的属性,每个属性都不同。

例如。这些可能是资产:

1.)
type:workbench
cost:200
vendor:Acme Co.
color:black
2.)
type:microscope
serial_no:BH-00102
purchase_date:1337800923
cost:2040

这可能会持续到成百上千种不同类型的资产。

如何以易于查询的标准化方式存储此类数据,而无需在每次添加新资产类型时更改我的表?一些字段也存在于所有资产中,例如成本。

到目前为止,我认为我应该拥有:

assets
id,cost,purchase_date,asset_type_id

asset_types
id,name

division_assets
division_id,asset_id

user_assets
user_id,asset_id

但我不知道将变化的数据放在哪里

【问题讨论】:

  • 一个属性可以与资产数量相关吗?
  • 某些属性适用于所有资产,但所有其他属性不适用于个别资产类型。
  • 你要搜索那些变量属性吗?另外,请阅读EAV
  • 如果你使用 Postgres,你可以使用 hstore 模块,它非常有效。
  • @TiagoMartinsPeres:在 2022 年,使用 jsonb 可能会更好

标签: mysql sql normalization rdbms


【解决方案1】:

我建议这样做:

assets (

   id
   asset_type_id
   vendor_id
   cost
   purchase_date

)

asset_poperties (

    id
    asset_id
    asset_property_type_id
    value

)

asset_property_types (

     id
     property_type

)

asset_types (

   id
   asset_type

)

vendors (

   id
   vendor

)

【讨论】:

  • 这不允许可变字段
  • 因此,发生变化的属性进入 assets 表,而常见的属性存储在单独的表中(asset_types、vendors 等),并通过外键链接到 assets 表。跨度>
  • 但是用户可以添加附加不同数据的资产类型,但我不希望用户能够改变数据库的结构。
  • 您可以创建一个像asset_properties 这样的附加表,其中包含字段id、asset_property_type、value,然后将其链接到资产表。
  • 我想过,但它会产生非常尴尬的查询。
【解决方案2】:

您可以为asset_metadata添加另一个表

asset_metadata
asset_metadata_id,asset_id,metadata_name,metadata_value

如果你想对元数据进行规范化和分类,可以这样规范化:

asset_metadata
asset_metadata_id,asset_id,metadata_name_id,metadata_value

metadata_name
metadata_name_id,metadata_name_text

【讨论】:

    【解决方案3】:

    我建议将成本等常见属性放在常规列中。然后再添加一列,在其中放置所有其他可变资产属性的序列化集合。

    CREATE TABLE assets (
      asset_id INT AUTO_INCREMENT PRIMARY KEY,
      cost NUMERIC(9,2),
      purchase_date DATE,
      variables TEXT
    );
    

    您可以将集合序列化为 JSON 或 XML 或任何您想要的。使用您的应用程序代码最容易处理的任何内容。

    INSERT INTO assets VALUES (123, 49.95, CURDATE(), 'color: black; vendor: Acme Co.');
    

    优点是您可以随时向文本 blob 添加新属性。缺点是不能读取或写入单个属性,必须将整个集合视为一个块。

    但您可以索引单个属性以使其可搜索。您需要为每个要搜索的属性创建一个新表(但这可能是所有属性的一小部分):

    CREATE TABLE asset_color (
      asset_id INT NOT NULL,
      color VARCHAR(10),
      PRIMARY KEY (asset_id, color),
      KEY(color)
    );
    

    并非所有资产都记录在此表中,只有那些具有颜色的资产。

    然后您可以对所有具有颜色属性的资产进行索引搜索:

    SELECT assets.*
    FROM assets INNER JOIN asset_color USING (asset_id);
    

    您还可以对具有颜色属性且颜色为黑色的资产进行索引搜索:

    SELECT assets.*
    FROM assets INNER JOIN asset_color USING (asset_id)
    WHERE color = 'black';
    

    真的没有办法设计一个允许变量属性的规范化数据库。所有范式首先要求表是一个关系。并且根据定义,关系必须具有一组固定的属性。

    其他人推荐 EAV 表,但 EAV 中的“值”列不符合具有类型的关系列的定义(其他后果是约束在 EAV 表中不起作用) .因此EAV表不是关系,也不能满足任何范式。

    【讨论】:

    • 将序列化的属性放入单个列也不是规范化的:它违反了第一范式(原子值)。无论如何,用规范化形式的关系数据库解决这个问题是不可能的。
    【解决方案4】:

    当我过去遇到这种情况时,“最佳”答案总是会根据我想要在数据库中执行多少处理,以及在客户端代码中执行多少而有所不同。

    对于它的价值,过去对我来说最有效的方法通常是每个可选属性都有一个表(特别是每个实体类型不是一个表)。所以,在你上面的例子中

    assets (as per your example)
    asset_types (as per you example)
    division_assets (as per your example)
    user_assets (as per your example)
    colours
      asset_id, colour
    weights
      asset_id, weight
    serial_numbers
      asset_id, serial_number
    

    当然,根据您需要做出的权衡,这对您来说可能是一个糟糕的选择。就我个人而言,我喜欢尽可能明确地保持数据架构,包括数据类型和约束,因此下次出现新属性时,我无需更改表。

    【讨论】:

      【解决方案5】:

      您可以创建两个新表:

      1) 在下表中定义多个资产属性(尽可能多的资产)

      asset_id

      资产属性

      资产价值

      2) 资产属性表

      attribute_id

      资产属性

      逻辑是asset_attributes 需要首先在asset_attribute 表中定义,然后它可以与任何资产一起使用(链接/标记)(作为外键,来自UI 上的下拉列表)和适当的输入的值。

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-19
        • 2011-05-29
        • 1970-01-01
        • 2016-08-09
        • 1970-01-01
        • 1970-01-01
        • 2019-12-10
        • 2015-03-20
        相关资源
        最近更新 更多