我正在为我的公司创建一个数据库,该数据库将存储许多不同类型的信息。类别是亮度,对比度,色度等。每个类别都有一些我的公司想要开始存储的数据点。
通常,我会为每个类别创建一个表来存储相应的数据。(这就是我学会这样做的方式)。但是,有时这些类别有“子数据”,这会改变每个表中所需字段的数量。
那么我的问题是,人们在构建数据库时如何处理数据的不一致?他们只是继续为额外的数据添加更多表格,还是完全不同?
我正在为我的公司创建一个数据库,该数据库将存储许多不同类型的信息。类别是亮度,对比度,色度等。每个类别都有一些我的公司想要开始存储的数据点。
通常,我会为每个类别创建一个表来存储相应的数据。(这就是我学会这样做的方式)。但是,有时这些类别有“子数据”,这会改变每个表中所需字段的数量。
那么我的问题是,人们在构建数据库时如何处理数据的不一致?他们只是继续为额外的数据添加更多表格,还是完全不同?
关于关系数据库模型有一些(谢天谢地只有少数)不可更改的规则。其中之一是,如果您不知道要存储什么,则很难存储它。很有可能,您将更难检索它。
也就是说,业务规则的现实往往不如数据库设计的象牙塔那么清晰。最重要的是,您可能想要甚至需要一种在不更改架构的情况下引入新属性的方法。
这里有两种可行的方法:
假设为了论证,您的产品总是有 (unique string) name
, (integer) id
, brightness
, contrast
,有时chromaticity
加上(integer)和 (string) ,考虑这些表foo
bar
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
brightness INT,
contrast INT,
chromaticity INT,
UNIQUE INDEX(name)
);
CREATE TABLE properties (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
proptype ENUM('null','int','string') NOT NULL default 'null',
UNIQUE INDEX(name)
);
INSERT INTO properties VALUES
(0,'foo','int'),
(0,'bar','string');
CREATE TABLE product_properties (
id INT PRIMARY KEY AUTO_INCREMENT,
products_id INT NOT NULL,
properties_id INT NOT NULL,
intvalue INT NOT NULL,
stringvalue VARCHAR(250) NOT NULL,
UNIQUE INDEX(products_id,properties_id)
);
现在您的“标准”属性将products
像往常一样在表中,而“可选”属性将存储在product_properties
引用产品 id 和属性 id 的行中,值在intvalue
or中stringvalue
。
选择产品,包括他们的产品foo
(如果有的话)
SELECT
products.*,
product_properties.intvalue AS foo
FROM products
LEFT JOIN product_properties
ON products.id=product_properties.product_id
AND product_properties.property_id=1
甚至
SELECT
products.*,
product_properties.intvalue AS foo
FROM products
LEFT JOIN product_properties
ON products.id=product_properties.product_id
LEFT JOIN properties
ON product_properties.property_id=properties.id
WHERE properties.name='foo' OR properties.name IS NULL
请理解,这会导致性能损失 - 事实上,您会在性能与灵活性之间进行交易:添加另一个属性只不过是在INSERT
ing 中插入一行properties
,架构保持不变。
如果您不是 mysql 绑定,那么其他数据库具有表继承或数组来解决某些特定情况。Postgresql是一个非常好的数据库,您可以像使用 mysql 一样轻松自由地使用它。
使用 mysql,您可以:
更改您的表,添加额外的列并在您不需要的子类别数据中允许 NULL。这种方式可以检查完整性,因为您仍然可以对列施加约束。除非您确实以这种方式拥有很多子类别列,否则我建议您这样做,否则选择 3。
将子类别数据动态存储在单独的表中,该表具有 category_id、category_row_id、subcategory 标识符(=子类别的类型)和值列:这样您就可以通过 category_id(确定表)和 category_row_id(链接到原始类别表行的PK)。坏事:你不能正确使用外键或约束来强制完整性,你需要编写毛茸茸的插入/更新触发器来仍然有一些控制,这将把完整性检查和引用检查的负担单独推到客户端上. (在这种情况下,您最好选择 NoSQL 路线)简而言之,我不推荐这样做。
您可以为每个类别表创建一个单独的子类别表,列可以通过值列 + 可选子类别标识符固定或可变,仍然可以使用外键,最好保持完整性是固定的,因为您将拥有完整的范围您可以使用的限制条件。如果您有很多子类别列,否则可能会弄乱您的常规子类别表,那么我建议将其与固定列一起使用。像之前的选项一样,我绝不建议对一次性数据以外的任何内容进行动态处理。
或者,如果您的子类别非常多变且易变:将NoSQL与文档数据库(如mongodb )一起使用,请注意,您可以将所有常规数据保存在适当的 RDBMS 中,并且只在文档数据库中存储侧数据,尽管这可能不推荐。
如果您的子类别数据处于已知的固定状态并且不易更改,我只需将额外的列添加到特定的类别表中。请记住,适当的 DBMS 的主要功能是通过检查和约束来保护数据的完整性,取消它从来都不是一个好主意。
如果您不限于 MySQL,您可以考虑使用 Microsoft SQL 服务器并使用稀疏列 这将允许您扩展架构以包含所需的任意数量的列,而不会对与给定行不相关的列产生存储损失。