我正在寻找一种特定的“最佳实践”或“模式”,涉及在不同实体之间共享的实体,与其中一个实体有关系。
例如,一个人可能有通用实体“地址”,它可用于存储客户、供应商、员工等的公共地址字段......
经验丰富的 DBA 会采用这种方式还是愿意将字段添加到相应的实体中?我也在考虑可维护性,可能(在未来)因实体而异的约束,诸如此类。
我很想获得有关该主题的任何权威或已建立作品的参考。
我正在寻找一种特定的“最佳实践”或“模式”,涉及在不同实体之间共享的实体,与其中一个实体有关系。
例如,一个人可能有通用实体“地址”,它可用于存储客户、供应商、员工等的公共地址字段......
经验丰富的 DBA 会采用这种方式还是愿意将字段添加到相应的实体中?我也在考虑可维护性,可能(在未来)因实体而异的约束,诸如此类。
我很想获得有关该主题的任何权威或已建立作品的参考。
将各种地址堆积到一个表中的动机通常是对代码重用概念的误解和误用。
人们可能会错误地假设,因为您有两个具有某些共同属性集的实体,所以这些属性属于它们自己的表。有时实体巧合地具有相似或相同的列。人们不会为数据库中的每个
NAME
或DESCRIPTION
或创建一个表EFFECTIVE_DATE
,至少我希望人们不会被诱惑这样做。有些人错误地将所有将列删除到他们自己的表中的实例称为规范化。规范化涉及将列删除到它们自己的表中,但并不是每个以这种方式删除列的实例实际上都是规范化。规范化规定了从表中删除列的非常具体的原因。如果这些原因都不适用,那么您就没有正常化,您只是让事情变得复杂。
你有两种正确的思考方式:要么你的地址都属于一堆,因为你有一个实体超类型,它包含几个实体子类型的所有共同特征,包括地址, - 或者 - 你的地址属于不同的堆(表)根据每种具有地址的事物,您针对为每个地址表实现的 IAddress 接口编写程序代码。
如果您实际上有一个实体超类型,比如
LEGAL_ENTITY
它有 、 等子类型CUSTOMER
,VENDOR
那么EMPLOYEE
拥有一个ADDRESS
子表LEGAL_ENTITY
是一种合法的方法。如果您的客户、供应商、员工(或您正在跟踪的任何对象)之间存在显着重叠,这甚至可能是一种有价值的方法,因为您可以一次更改地址,而不是在法人搬迁时更改多个位置。另一方面,如果你没有这样的超级类型,那么你将面临理查德塔伦特指出的问题。如果根据拥有地址的实体类型将地址保存在不同的表中,那么假设您使用的语言支持接口,您仍然可以实现代码重用。
顺便说一句:tvCa 在评论中指出地址可以存储为列而不是单独表中的行。这在很大程度上取决于每个实体需要多少个地址。如果您正在跟踪两个地址(物理地址、邮寄地址)或者如果您正在存储地址历史记录,那么请使用地址表。如果您只为每个收件人存储一个地址,那么一个单独的表可能有点矫枉过正。
我不能指出任何权威性,但如果您仔细考虑这种实施的细节,潜在的缺点是显而易见的。
拥有一个“共享”子表是有问题的,主要是因为如果两个“父”表(比如,
Customer
和Employee
)都使用同一个Address
表来存储地址,则不能使用外键约束来确保地址记录和相应的父记录。即使您放弃使用外键约束,在设置外键列时也会遇到一些难题。您基本上有三种选择,但都不是理想选择:
AddressID
在 Customer 和 Employee 表中放置一个字段。这里的问题是(1)你不能保证一个地址不会被多次使用,(2)如果AddressID
是自动分配的,你不能将地址存储在客户/员工表中,直到地址已创建,这与您可能希望插入记录的方式相反(即,它创建Address
了“父”表)。在表中放置
CustomerID
和EmployeeID
列Address
。这里的问题包括 (1) 再次,您不能保证重复使用一个地址,(2) 它浪费空间,因为您在一列或另一列中存储 NULL,以及 (3) 它不能很好地扩展当您发现更多需要地址的实体时。折叠 CustomerID/EmployeeID/等。分为单列
ParentID
和另一列,ParentTypeID
以区别于Customers
.Employees
这比上面的 (2) 更好,但有其自身的问题,例如需要为ParentTypeID
.我不会说这种方法在任何地方都不实用,但您必须考虑在多个表中拥有相似的列是否真的有那么大的问题,以及是否真的试图将它们移动到一个公用表为插入、更新、连接等增加的复杂性买任何东西。恕我直言,通常每个表最好在它们与其他表的关系方面有明确的约束,并且“父”表代表正在创建的核心业务对象(客户、员工等),而不是碰巧为其他几个表所共有的附属复杂类型。