实体关系设计;最好的场景

mul*_*uin 5 erd normalization database-design

TLDR;以下场景的最佳设计选择是什么,每个设计在极大数据量下会如何反应?

我有使用大型政府数据库系统服务 24/7 数据收集、处理和报告的经验。浏览所有不同设计的模式并了解所有这些不同的人设计的所有这些功能如何以某种方式混杂成一个有效的解决方案是很有趣的。就像我相信你们中的一些人知道的那样,有趣的戳时间是一种奢侈,而且大多数周期都是务实的,让系统保持活力而不是改进设计。

我一直在建模一个新的数据库系统,并想对如何关联这些实体有一些想法。


场景:客户、雇主和从业者需要电话号码

我们有四个实体:

  • CLIENT
  • EMPLOYER
  • PRACTITIONER
  • PHONE

我们的初始实体

电话号码按用于接听电话的技术进行分类,所使用的技术通知数据格式限制。

  • 座机
  • 传真
  • 移动的

描述字段指示电话的主要用途;家庭、工作等。


关联这些实体的方法

1. 反规范化PHONECLIENT, EMPLOYER,PRACTITIONER

让我们从糟糕的设计开始,然后从那里开始。去规范化所有的电话号码!

非规范化表

  • 3 个实体,没有关系
  • 如果需要新电话号码,则必须创建新列;导致CLIENT.Phone1Number, EMPLOYER.Phone2Type, PRACTITIONER.Phone3Description;
  • 限制可以为每个实体输入的电话号码数量
  • 冗余,大量开销
  • 进行批量更新或维护会变得乏味

结论:select * from 'no_thanks';


2.建造第n座桥;重命名数据库匹兹堡

对于可以关联电话号码的每个实体,创建一个桥实体将它们组合在一起。

天桥表

  • 7 个实体,6 个关系
  • 数据冗余;电话号码填充在多个位置
  • PhoneNumber在需要时可以使用桥接表;不需要 JOIN 即可PHONE
  • 如果新实体FAMILYMEMBER需要电话号码,则必须创建新的桥接表

结论:也许,取决于维持关系的难度


3. 一个准“星图”

修改PHONE以包含CLIENT.ClientID, EMPLOYER.EmployerID, 的外键PRACTITIONER.PractitionerID

另一个维度

  • 4 个实体,3 个关系
  • 如果填充了这些键之一,则无法填充其他键。(客户、雇主、从业者不会有相同的电话号码
  • 如果新实体FAMILYMEMBER需要电话号码,则必须在PHONE
  • 默认情况下所有 FK 属性都为NULL

结论:在我看来似乎是最强的设计

jya*_*yao 2

如果我真的必须选择,我会说你的第二个选择(建造第n座桥)将是我最喜欢的,因为它很干净并且遵守规则。虽然您的第三个选择虽然减少了表的数量,但它实际上在电话表中带来了带有空值的“冗余”列,并且这种设计是“易失性”的,因为如果您需要添加新的电话所有者类型,您需要在 [Phone] 表中添加一个附加列。

以另一种方式,我将创建一个如下所示的“桥”表(以 t-sql 为例):

    create table PhoneOwner (ID int identity primary key
    , OwnerID int 
    , OwnerType varchar(20));
Run Code Online (Sandbox Code Playgroud)

因此,对于 [Phone] 表,我将添加一列 PhoneOwnerID,它引用 [PhoneOwner] 表的 [ID] 列。在本例中, OwnerType列可以具有“客户”、“雇主”或“从业者”的值,或者将来的其他值。(当然,我们可以创建[OwnerType]表来保存这些值,并在[PhoneOwner]表中放置一个FK来引用这个[OwnerType]表)

这种替代设计的问题在于完整性检查,例如如果OwnerType = 'Client',我们需要确保OwnerID的值确实存在于[Client]表中,尽管这可以通过应用层或通过触发器来实现此类业务规则。

但我不得不承认这是对严格完整性(通过 FK)规则的妥协,好的一面是它以某种方式实现了更好的灵活性,并且减少了表设计中的混乱,这将导致“冗余”列中出现许多空值。