在SQL Server中实现多态关联的最佳方式是什么?

我有大量的实例,我需要在我的数据库中实现某种多态关联。 我总是浪费大量的时间重新思考所有的选项。 这是我能想到的3个。 我希望有一个SQL Server的最佳做法。

这是多列方法

多列方法

这是没有外键的方法

没有外键方法

这里是基本的方法

基表方法

最常见的两种方法是Table Per Class(即基类的表和每个子类的另一个表,包含描述子类所需的附加列)和Table Per Hierarchy(即每个表中的所有列,一个或多个列允许区分子类,哪一个更好的方法取决于应用程序和数据访问策略的细节。

在第一个例子中,您将拥有Table Per Class,方法是颠倒FK的方向,并从父项中移除额外的id。 另外两个实质上是每个class级的变体。

这个模型的另一个通用名称是超types模型,其中一个具有一组基本属性,可以通过连接到另一个实体进行扩展。 在Oracle书籍中,它被教导为一个逻辑模型和物理实现。 没有关系的模型将允许数据增长到无效状态和孤立logging,我会强烈validationselect该模型之前的需求。 存储在基础对象中的关系的顶层模型会导致空值,如果字段是互斥的,则总会有空值。 在子对象中强制执行键的底部图将消除空值,但也会使依赖关系成为一种软性依赖性,如果不强制级联,则允许孤儿。 我认为评估这些特征将帮助您select最适合的模型。 我过去都用过这三个。

根据我的观点,你的第一种方法是你可以定义数据和你的类的最好方法,但是因为你所有的主要数据都应该为孩子所用。

所以你可以检查你的需求并定义数据库。

我已经使用了我想你会称之为基表的方法。 例如,我有名字,地址和电话号码的表格,每个表格的身份都是PK。 然后,我有一个主要的实体表实体(entityID)和一个链接表:attribute(entityKey,attributeType,attributeKey),其中attributeKey可以指向前三个表中的任何一个,具体取决于attributeType。

一些优点:允许每个实体尽可能多的名称,地址和电话号码,容易添加新的属性types,极端标准化,易于挖掘共同属性(即识别重复的人),一些其他业务特定的安全优势

缺点:构build简单结果集的相当复杂的查询使得难以pipe理(即,我用T-SQL足够好的人员招聘麻烦); 对于非常特定的用例,性能是最佳的,而不是一般的; 查询优化可能会非常棘手

在这样的架构下工作了好几年,我不愿再使用它,除非我有相同的怪异的业务逻辑约束和访问模式。 对于一般用法,我强烈build议你的types表直接引用你的实体。 也就是Entity(entityID),Name(NameID,EntityID,Name),Phone(PhoneID,EntityID,Phone),Email(EmailID,EntityID,Email)。 你将有一些数据重复和一些共同的列,但编程和优化会更容易。

方法1是最好的,但是东西和对象1,对象2,对象3之间的关联应该是一对一的。

我的意思是孩子(object1,object2,object3)表中的FK应该是非空的唯一键或子表的主键。

object1,object2,object3可以有Polymorphic对象的值。

没有单一或普遍的最佳做法来实现这一点。 这一切都取决于应用程序将需要的访问types。

我的build议是对这些表格的预期访问types进行概述:

  1. 你会使用OR层,存储过程还是dynamicSQL?
  2. 你期望什么数量的logging?
  3. 不同的亚类之间有什么区别? 多less列?
  4. 你会做汇总或其他复杂的报告?
  5. 你将有一个数据仓库进行报告吗?
  6. 您是否经常需要在一批中处理不同子类的logging? …

根据这些问题的答案,我们可以找出一个合适的解决scheme。

存储特定于子类的属性的另外一种可能性是使用具有名称/值对的表。 如果存在大量不同的子类或子类中的特定字段不经常使用,则此方法可能特别有用。

我已经使用了第一种方法。 在极端负载下,“东西”表成为瓶颈。

我采取了使用模板DDL的方法来为不同的对象添加属性特化项,并将其添加到表定义的末尾。

在数据库层面,如果我真的需要将我的不同类别表示为“某些”logging集,那么我将其视为顶部

SELECT "Something" fields FROM object1 UNION ALL SELECT "Something" fields FROM object2 UNION ALL SELECT "Something" fields FROM object3 

挑战是如何分配一个非冲突的主键,因为你有三个独立的对象。 通常情况下,人们使用UUID / GUID,但在我的情况下,密钥是基于时间和机器在应用程序中生成的64位整数,以避免冲突。

如果你采取这种方法,那么你就避免了“Something”对象导致locking/阻塞的问题。

如果你想改变“东西”对象,那么现在你有三个独立的对象,这将是尴尬的,所有这些都将需要改变他们的结构。

所以总结一下。 选项一将在大多数情况下工作正常,但是在严重的负载下,您可能会观察到需要拆分devise的locking阻塞。

方法1与多列外键是最好的一个。 因为这样你就可以与其他表进行预先定义的连接。这使得脚本更容易select,插入和更新数据。