【问题标题】:Table-Per-Type Database Design AdviceTable-Per-Type 数据库设计建议
【发布时间】:2013-04-20 21:58:39
【问题描述】:

我正在寻求有关设计数据库的建议,该数据库具有希望与其他几种不同实体类型相关的通用实体。可怕的介绍句,我知道……所以请让我举例说明。

考虑我有两个不同的实体Employees 和Customers 表defs:

Employees
----------
EmployeeID int PK
FirstName varchar
LastName varchar
... other Employee specific fields

Customers
----------
CustomerID int PK
FirstName varchar
LastName varchar
... other Customer specific fields

更好的设计可能会在相关的基表中包含常用字段 FirstName 和 LastName,但这不是我正在努力解决的部分。

现在,考虑我希望能够为我的员工和客户存储无限数量的地址和电话号码,并定义表:

Addresses
----------
AddressID int PK
AddressLine varchar
City varchar
State varchar
PostalCode varchar

PhoneNumbers
-------------
PhoneNumberID int PK
PhoneNumber varchar
PhoneExtension varchar

然后是另外两个表格,用于将地址和电话号码与员工联系起来:

EmployeeAddresses
------------------
EmployeeAddressID int PK
EmployeeID int FK Employees.EmployeeID
AddressID int FK Addresses.AddressID
EmployeeAddressType enum

EmployeePhoneNumbers
---------------------
EmployeePhoneNumberID int PK
EmployeeID int FK Employees.EmployeeID
PhoneNumberID int FK PhoneNumbers.PhoneNumberID
EmployeePhoneNumberType enum

还有两个相似的表 CustomerAddresses 和 CustomerPhoneNumbers,用于将 Addresses 和 PhoneNumbers 与 Customers 表相关联。 Addresses 和 PhoneNumbers 的任何特定于员工或特定于客户的方面,例如上面的 EmployeeAddressType,也会出现在最后四个表中。

根据我对 Internet 的研究发现,这种设计称为 Table-Per-Type (TPT) 或 Table-Per-Subclass (TPS)。而且多态的优势似乎很有吸引力,例如,我可以将 AddressLine2 添加到 Addresses 表中,我的 Employess 和 Customers 都会自动获得额外地址行的好处。

那些关于 TPT 的消息来源指出的缺点是查询速度较慢且难以实施。现在我相当开放式的请求建议......

我没有考虑哪些其他缺点?您在尝试维护和改进基于此设计的应用程序时会遇到什么问题?最后,上面的设计是大多数有经验的数据库设计师会使用的吗?

谢谢。

【问题讨论】:

    标签: sql database database-design


    【解决方案1】:
    1. 使用单表继承启动。它是最简单、最简单、最快的。

    2. 使用派对模式。个人和组织都是当事人,可以扮演客户或员工的角色。

    3. 将电子邮件地址、电话号码、网站和邮寄地址都视为“联系方式”或地址的子类型。

    4. 如果您使用 JBoss Hibernate (java) 或 NHibernate (.net) 之类的工具,那么这会为您完成大部分工作。

    【讨论】:

    • 感谢您的回复,尼尔。我不熟悉单表继承。老实说,我的 C++ 程序员在想到一张包罗万象的表格时有点畏缩。但我可以想象它的简单、速度和易于扩展的好处,因此不禁考虑采用这种方法。再次感谢。
    【解决方案2】:

    最好从 People 表开始,然后是 customers 表、employees 表等。然后,电子邮件地址、地址和电话号码将与 people 表相关,而不是与 customer 或其他一些专门的表相关。

    一个地址表与多个父表相关的问题是您无法设置正确的外键约束,并且总是会得到错误的数据。

    您可以使用单独的表正确创建外键,但查询变得更加困难(假设您需要了解 CA 中的每个人),您会为最终属于多个类别的人获得重复记录(员工也可能是客户)当需要更改表结构时,更难确保表全部更新。

    【讨论】:

    • 感谢 HLGEM,我将计划一个基本的 People 表。但是我将地址直接与人员表相关联的问题是我有专门针对人员子类的地址。例如,“送货”地址的 CustomerAddressType 仅适用于客户的地址记录。我怎样才能拥有这个特定于子类的信息,并将地址直接关联到 People 表?
    • 您可以在您的用户界面中强制执行(如果他们不是客户,则不让人们选择插入该地址类型)或使用触发器来强制执行。或者两者都做。
    【解决方案3】:

    您当前数据库设计的一个缺点是您的数据库不会阻止员工拥有 2 个或更多家庭住址。它也不会阻止客户在这方面没有地址。

    您可以通过更改 EmployeeAddresses 表中的复合主键(PK = EmployeeID, EmployeeAddressType)来防止创建多个家庭地址。但是,如果您使用的是 ORM,它们中的许多只有在 PK 为一列时才能发挥作用。

    【讨论】:

    • 有点跑题了,但是您知道哪些 ORM 存在复合 PK 问题?我只使用过 Hibernate,从来没有遇到过问题。这似乎是一个 ORM 应该能够处理的非常基本的事情。
    • 据我了解,Hibernate 是少数可用于复合 PK 的 ORM 之一。我知道 Massive、SubSonic、PetaPOCO、DJango 都不支持它们。
    【解决方案4】:

    Employees 和 Customers 都是 People 类的子类,如前面的回复中所述。这两个子类可能并不相互排斥。

    有一种技术,称为类表继承。在这种技术中,将有三个表,人员、员工和客户。所有人共有的属性(例如地址)将位于“人员”表中。

    您可以通过访问此标签获取详细信息 并查看“信息”标签。

    【讨论】:

    • 感谢您的回复。是的,类表继承听起来更像我的想法。请参阅我对 HLGEM 的回复 - 我将地址直接与人员相关联的问题是我对每个人的子类都有特定的地址。
    • 如果您认为这是正确答案,您可以将其标记为正确,即使您没有投票权。
    • 啊哈!将此响应标记为正确,因为它命名了数据建模方法 - 类表继承。此外,根据 HLGEM 的建模策略,提供了良好的信息和建议。感谢大家的反馈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多