什么样的遗产数据库的设计
题
假设你是设立一个数据库来存储的碰撞测试的数据的各种车辆。你要存储数据的碰撞测试用快艇、轿车和卡丁车。
你可以创建的三份单独的表格:SpeedboatTests,CarTests,并GokartTests.但很多你的列都将是相同的,在每个表格(例如,员工身份的人员进行测试,向冲突(前面、侧面,后),等等)。然而,大量的列有所不同,所以你不想只是把所有的检验数据在一个单一的表,因为你会有不少列将永远是无用的快艇,好几个,这将永远是空的汽车,以及相当多的,总是会null卡丁车。
让我们说你还想要储存一些信息,是不是直接相关的试验(例如雇员身份证的设计师事情正在测试)。这些列似乎没有权利放在一个"测试",表在所有人,特别是因为它们只是重复所有的测试在同一车辆。
让我说明一种可能的安排的表格,所以你可以看到的问题的参与。
Speedboats id | col_about_speedboats_but_not_tests1 | col_about_speedboats_but_not_tests2 Cars id | col_about_cars_but_not_tests1 | col_about_cars_but_not_tests2 Gokarts id | col_about_gokarts_but_not_tests1 | col_about_gokarts_but_not_tests2 Tests id | type | id_in_type | col_about_all_tests1 | col_about_all_tests2 (id_in_type will refer to the id column of one of the next three tables, depending on the value of type) SpeedboatTests id | speedboat_id | col_about_speedboat_tests1 | col_about_speedboat_tests2 CarTests id | car_id | col_about_car_tests1 | col_about_car_tests2 GokartTests id | gokart_id | col_about_gokart_tests1 | col_about_gokart_tests2
什么是好坏关于这个结构,这将是首选的方式执行这样的事情?
如果还有一些信息适用于所有车辆,你会喜欢在一个车辆表?会CarTests表然后看起来像...
id | vehicle_id | ... With a Vehicles table like this: id | type | id_in_type (with id_in_type pointing to the id of either a speedboat, car, or go-kart)
这只是越来越成为一个皇家混乱,它似乎。应该如何像这样的东西可以成立?
解决方案
这 type
和 id_in_type
设计被称为 多态关联. 。这种设计以多种方式打破了标准化规则。如果不出意外的话,这应该是一个危险信号,您 不能 声明一个真正的外键约束,因为 id_in_type
可以引用几个表中的任何一个。
这是定义表的更好方法:
- 制作一个抽象表
Vehicles
为所有车辆子类型和车辆测试提供抽象参考点。 - 每个车辆子类型都有一个主键,该主键不会自动递增,而是引用
Vehicles
. - 每个测试子类型都有一个主键,该主键不会自动递增,而是引用
Tests
. - 每个测试子类型还具有对应车辆子类型的外键。
这是示例 DDL:
CREATE TABLE Vehicles (
vehicle_id INT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE Speedboats (
vehicle_id INT PRIMARY KEY,
col_about_speedboats_but_not_tests1 INT,
col_about_speedboats_but_not_tests2 INT,
FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);
CREATE TABLE Cars (
vehicle_id INT PRIMARY KEY,
col_about_cars_but_not_tests1 INT,
col_about_cars_but_not_tests2 INT,
FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);
CREATE TABLE Gokarts (
vehicle_id INT PRIMARY KEY,
col_about_gokarts_but_not_tests1 INT,
col_about_gokarts_but_not_tests2 INT,
FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);
CREATE TABLE Tests (
test_id INT AUTO_INCREMENT PRIMARY KEY,
col_about_all_tests1 INT,
col_about_all_tests2 INT
);
CREATE TABLE SpeedboatTests (
test_id INT PRIMARY KEY,
vehicle_id INT NOT NULL,
col_about_speedboat_tests1 INT,
col_about_speedboat_tests2 INT,
FOREIGN KEY(test_id) REFERENCES Tests(test_id),
FOREIGN KEY(vehicle_id) REFERENCES Speedboats(vehicle_id)
);
CREATE TABLE CarTests (
test_id INT PRIMARY KEY,
vehicle_id INT NOT NULL,
col_about_car_tests1 INT,
col_about_car_tests2 INT,
FOREIGN KEY(test_id) REFERENCES Tests(test_id),
FOREIGN KEY(vehicle_id) REFERENCES Cars(vehicle_id)
);
CREATE TABLE GokartTests (
test_id INT PRIMARY KEY,
vehicle_id INT NOT NULL,
col_about_gokart_tests1 INT,
col_about_gokart_tests2 INT,
FOREIGN KEY(test_id) REFERENCES Tests(test_id),
FOREIGN KEY(vehicle_id) REFERENCES Gokarts(vehicle_id)
);
你也可以声明 Tests.vehicle_id
哪些参考文献 Vehicles.vehicle_id
并删除每个测试子类型表中的vehicle_id外键,但这将允许异常,例如引用gokart id的快艇测试。
其他提示
有关映射继承层次到数据库表,我觉得Martin Fowler的勾画出了相当的替代品以及在他的企业应用架构模式书
http://martinfowler.com/eaaCatalog/singleTableInheritance.html
http://martinfowler.com/eaaCatalog/classTableInheritance.html
http://martinfowler.com/eaaCatalog/concreteTableInheritance.html
如果附加字段/列的数目是小的子类,那么单个表继承通常是最简单的处理。
如果你正在使用PostgreSQL为你的数据库和你愿不愿意把自己绑在一个特定的数据库功能,它支持表继承直接:
我将其拆分成不同的表,例如车辆(ID,类型等)VehicleAttributes()VehicleID,属性Id,值),CrashTestInfo(VehicleID,CrashtestID,日期等)CrashtestAttributes(CrashTestID,属性Id,值)
或者而不是属性,单独的表的每个组相似的细节应记录。
如果您使用 SQLAlchemy, 目关系映射对蟒蛇,你可以 配置如何,继承的层次结构映射数据库表.对象关系映射是好驯服,否则繁琐SQL。
你的问题可能是一个很好的适用于垂直表。而不是储存中的一切的架构,保存对象的类型和主要关键之一表和key/value组对每个对象中的另一个表中。如果你真的是储存汽车测试,这种设置将使它更容易添加新的种类的结果。
请在“根规格的关系建模”谷歌搜索。你会发现如何设置存储的通用实体(什么OO程序员可能调用父类),分别为每个专业实体表(子类),以及如何使用外键链接它的属性表文章都在一起。
最理想的用品,国际海事组织,讨论ER建模方面根规格。如果你知道如何翻译的ER模型转换为关系模型,并从那里向SQL表,你就知道该怎么做,一旦他们告诉你如何根规格的ER模型。
如果你只是在“根规格的”谷歌的大部分东西,你会看到的是面向对象的,而不是面向关系。你知道如何克服对象关系阻抗失配的东西可能是有用的,因为长。
您设计合理并按照正确的规范化规则。您可能忽略了车辆ID和类型车辆表(用于快艇,汽车即“父”,和卡丁车......在这里你会保持这样的东西“DesignedByUserId”)。车辆表和快艇表之间是一个一 - 至 - 一个关系,和之间的车辆和快艇/汽车/卡丁车存在1且仅-1的关系(即,车辆只能有用于快艇1个结果,汽车或卡丁车)......虽然大多数分贝的没有为此提供了一个简单的执法机制。
一个规范化规则,可帮助识别这些各种各样的事情是,一个字段应仅在表中的主键依赖。在快艇,汽车和gokart测试结果存储在一起,然后合并表相关领域的汽车,不仅在测试日期,但也对运载工具ID和车辆类型的依赖。对于测试结果表的主键是测试日期+车辆ID和车辆类型不是什么使测试数据行唯一的(即反正是有进行上01/01/200912一个试验:在一个特定的车辆30PM既快艇和汽车......都能跟得上...不能完成)。
我不解释规范化规则particularily很好......但3/4/5的正常形式的规则总是混淆了我,当我读到的正式描述。其中一个(第三/第四/第5次)的与取决于主键和只有主键字段的交易。该规则使该主键已经被正确识别的假设(不正确地defininh主键是太容易做)。