Mysql 存储';元数据';在关系数据库中?

Mysql 存储';元数据';在关系数据库中?,mysql,sql,normalization,rdbms,Mysql,Sql,Normalization,Rdbms,我有一个名为资产的表,其中一个资产可以属于一个用户、团队或部门,也可能属于每个部门的多个。我的问题是,资产是高度可变的,并且可以具有与它们相关联的属性,每个属性都不同 例如,这些可能是资产: 1.) type:workbench cost:200 vendor:Acme Co. color:black 2.) type:microscope serial_no:BH-00102 purchase_date:1337800923 cost:2040 这可能会持续数百到数千种不同类型的资产 如何以

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

例如,这些可能是资产:

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
但是我不知道把不同的数据放在哪里,我建议:

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

)

您可以为资产元数据添加另一个表

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

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

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添加新属性。缺点是不能读取或写入单个属性,必须将整个集合视为一个整体

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

并非所有资产都记录在此表中,仅记录具有颜色的资产

然后,可以对具有颜色属性的所有资源执行索引搜索:

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';
实际上,没有办法设计一个允许变量属性的规范化数据库。所有范式都要求表首先是一个关系。根据定义,关系必须具有一组固定的属性

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

其他人建议使用EAV表,但EAV中的“value”列不符合类型为的关系列的定义(这种情况的其他后果是约束在EAV表中不起作用)。因此,EAV表不是一个关系,也不能满足任何标准形式。

当我在过去遇到这个问题时,“最佳”答案总是根据我希望在数据库中处理的数量和在客户端代码中处理的数量而有所不同

值得一提的是,过去最适合我的方法通常是每个可选属性有一个表(特别是,不是每个实体类型有一个表)。在上面的例子中

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

当然,根据您需要做出的权衡,这可能是一个错误的选择。就我个人而言,我喜欢让数据的模式尽可能明确,包括数据类型和约束,因此下次出现新属性时,我在更改表时没有任何戏剧性。

您可以创建两个新表:

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

资产标识

资产属性

资产价值

2) 资产属性表

属性标识

资产属性

逻辑是,首先需要在asset_属性表中定义asset_属性,然后可以将其与任何资产(作为外键,从UI上的下拉列表中)一起使用(链接/标记),并输入适当的值


希望这有帮助。

一个属性是否可以与资产数量相关?某些属性适用于所有资产,但所有其他属性不适用于单个资产类型。是否要搜索这些可变属性?此外,如果您正在使用Postgres,您可以使用hstore模块,该模块可以非常高效地执行此操作。这不允许使用变量字段。因此,确实发生更改的属性将进入资产表,而常见的属性将存储在单独的表中(资产类型、供应商等)并通过外键链接到assets表。但是用户可以添加附加了不同数据的资产类型,但我不希望用户能够更改数据库的结构。您可以创建一个添加表,如asset_properties,其中包含字段id、asset_property_type、,值,然后将该值链接到资产表。我考虑过这一点,但这会创建非常棘手的查询。将序列化属性放入一个列也不是标准化的:它违反了第一个标准形式(原子值)。用纯规范化形式的关系数据库解决这个问题无论如何都是不可能的。