我经常发现自己质疑在创建数据库和关系时是否采用正确的方法来规划未来的可扩展性。
我有以下情况:
我有一个Donor
表和一个Recipient
表。这两个表共享公共信息,例如first_name
,last_name
,email_address
,date_of_birth
等。如果您原谅我的面向对象语言,它们似乎共享一个常见的抽象类型Person
。某位Recipient
的某个人可能会通过捐赠的方式成为Donor
,因此重要的是不要在表格之间复制信息。我应该选择继承模式,还是应该将外键Donor
和Recipient
添加到Person
表?
最初,我在想简单地将email_address
等属性和街道地址属性直接映射到需要它们的东西,但是可能会出现一个人有多个电子邮件地址或邮寄地址的可能性(即:家庭,工作等)。这意味着我们有一个类似的模型:
create table person(id int primary key auto increment, ...,
default_email_address);
create table email_address(id int primary key auto increment,
email varchar(255), name varchar(255), is_default bool, person_id int);
这让事情变得有点复杂,你可以想象。 name
字段还包含默认值列表以及允许自定义输入。我不能只是把它变成一个enum字段,因为有可能有人会有很多电子邮件需要添加才能完全不同......(这就是我尖叫出来的那一点“它是否值得信赖它” !?!?“并对项目感到沮丧”
我想这真正归结为以下几点:数据规范化在什么时候变得荒谬可笑?我的目标是创建一个非常好的as-forward-compatible-as-possible数据模型,我不会自己创建以后创建。
答案 0 :(得分:7)
数据规范化在什么时候变得荒谬可笑?
它停止对实际要求进行建模。
举个例子:
使用Donor
和Recipient
表格,如果任何一个人很可能同时成为两者,那么分离出Person
实体是有意义的。如果这种情况很少见,则不会。
对于email_address
和street_address
情况,取决于您是否需要存储倍数(期望是什么?)。您可能希望为每个业务单位存储单独的版本(例如shipping_address
vs billing_address
)。
答案 1 :(得分:3)
我认为问题不在于您的实施,而在于您对问题的分析。 Donor
和Recipient
不是一流演员,他们是演员的角色。如果你这样建模,你会得到一个更简洁的模型:
person_donor
和person_recipient
添加到person
表中。答案 2 :(得分:2)
简短回答:规范化永远不会变得荒谬。你所做的大部分工作都不是规范化。
更长的答案
大多数设计师实际上可以做到的“最差”(事实上,“最好的”)最终会得到5NF中的所有牌桌.5NF根本不是荒谬的。(是的,我知道6NF。我忽略了它出于教学原因。)
质疑我是否采取正确的方法来计划 为了未来的可扩展性
这是一个问自己的好问题。但它与标准化无关。在概念层面,标准化是您在之后确定要确定哪些属性(列)和数据需要进入数据库。经验丰富的数据库设计人员经常“在3NF中思考”,或多或少地同时选择属性,数据和规范化。
我应该选择继承模式,还是应该只是外键 捐赠者和收件人到人员表?
捐赠者和接受者不是不同类型的人。捐赠者是捐款的人。收件人是收到某些东西的人。
id fullname don_date don_amt recip_date recip_amt
--
1 Jamie Hubbert 2012-01-13 $20.00
1 Jamie Hubbert 2012-02-13 $17.00
2 Kelly Hawkin 2012-01-13 $50.00
2 Kelly Hawkin 2012-01-13 $20.00
3 Neva Papke 2012-01-13 $15.00
3 Neva Papke 2012-02-13 $15.00
2 Kelly Hawkin 2012-01-13 $10.00
4 Jamie Hubbert 2012-01-13 $10.00
4 Jamie Hubbert 2012-02-13 $10.00
在规范化期间,您将识别这些依赖关系。 (为简单起见,假设每个人每个日期捐赠一次。)
标准化为5NF,您将获得这三个表。
Persons
--
1 Jamie Hubbert
2 Kelly Hawkin
3 Neva Papke
4 Jamie Hubbert
Donations
--
1 2012-01-13 $20.00
1 2012-02-13 $17.00
2 2012-01-13 $50.00
2 2012-01-13 $20.00
4 2012-01-13 $10.00
Receipts (?)
--
3 2012-01-13 $15.00
3 2012-02-13 $15.00
2 2012-01-13 $10.00
4 2012-02-13 $10.00
最初,我在考虑简单地映射属性 email_address和街道地址属性直接进入事物 需要它们,但随后可能会出现一个人的可能性 有多个电子邮件地址或邮寄地址(即:家庭,工作, 等)。
决定是否支持多个电子邮件地址,多个邮寄地址以及不同的邮寄和递送地址是一项重大的设计决策。但它与规范化无关。再次,标准化是您在之后确定哪些属性和数据属于您的数据库。因此,如果您正在收集代表性示例数据,则最终可能会使用这两组电子邮件地址中的一个。
Set A
1 Jamie Hubbert jhubbert@somedomain.com
4 Jamie Hubbert jamie.hubbert@this.com
Set B
1 Jamie Hubbert jhubbert@somedomain.com
1 Jamie Hubbert jamie@my.com
4 Jamie Hubbert jamie.hubbert@this.com
在集合A中,person_id->电子邮件。在集合B中,它没有。选择支持集合A中的数据或集合B中的数据是一个大决策,它会在规范化为5NF之后强烈影响您最终使用。但决定支持哪一套与规范化无关。
另外,选择将id号分配给非唯一的电子邮件地址是另一个重大(且有问题)的设计决策。与其他人一样,这一决定与规范化无关。
(随机名称由The Random Name generator提供。)
答案 3 :(得分:0)
我会将所有共享数据放入Person
表中。 Donor
和Recipient
表应仅包含特定于每个表的数据,并且应具有指向Person
主键的外键。
这根本不是荒谬的正常化;这实际上很常见。