在SQL Server中实现Polymorphic Association的最佳方法是什么?

时间:2011-08-09 17:28:56

标签: sql-server associations polymorphic-associations database-normalization

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

这是多列方法

Multiple Column approach

这是无外键方法

No Foreign Key Approach

这是基表方法

Base table approach

9 个答案:

答案 0 :(得分:3)

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

通过反转FK的方向并从父项中删除额外的ID,您将在第一个示例中使用Table Per Class。另外两个基本上是每个类的表变体。

答案 1 :(得分:2)

此模型的另一个常见名称是超类型模型,其中一个具有一组基本属性,可以通过连接到另一个实体进行扩展。在Oracle书籍中,它既是逻辑模型,也是物理实现。没有关系的模型将允许数据增长到无效状态和孤立记录,我会在选择该模型之前强烈验证需求。具有存储在基础对象中的关系的顶部模型将导致空值,并且在字段相互排斥的情况下,您将始终具有空值。在子对象中强制执行密钥的底部图将消除空值,但也会使依赖性成为软依赖性,并且如果未强制执行级联,则允许孤立。我认为评估这些特征将帮助您选择最适合的模型。我过去曾经使用过这三种颜色。

答案 2 :(得分:1)

我使用以下解决方案来解决类似的问题:

基于多对多的设计:即使该关系在ObjectN和Something之间是1-Many,也等效于对关系表PK进行修改的“多对多”关系。

首先,我在ObjectN和每个对象之间创建一个关系表,然后将Something_ID列用作PK。

这是Something-Object1关系的DDL,与Object2和Object3相同:

CREATE TABLE Something
(
    ID INT PRIMARY KEY,
    .....
)

CREATE TABLE Object1
(
   ID INT PRIMARY KEY,
   .....
)

CREATE TABLE Something_Object1
(
    Something_ID INT PRIMARY KEY,
    Object1_ID INT NOT NULL,
    ......

    FOREIGN KEY (Something_ID) REFERENCES Something(ID),
    FOREIGN KEY (Object1_ID) REFERENCES Object1(ID)
)

此票证multiple-foreign-keys-for-the-same-business-rule

中的更多详细信息和其他可能选择的示例

答案 3 :(得分:0)

据我所知,您的第一种方法是定义数据和类的最佳方法,但是您的所有主要数据应该对孩子有用。

因此,您可以检查您的要求并定义数据库。

答案 4 :(得分:0)

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

一些优点:允许每个实体使用尽可能多的名称,地址和语音,轻松添加新属性类型,极端规范化,易于挖掘常见属性(即识别重复人员),以及其他一些特定于业务的安全优势

缺点:构建简单结果集的相当复杂的查询使得难以管理(即我很难雇用具有足够好的T-SQL排骨的人);对于非常具体的用例而言,性能是最佳的,而不是一般的;查询优化可能很棘手

在更长的职业生涯中使用这种结构好几年之后,我会毫不犹豫地再次使用它,除非我有相同的奇怪的业务逻辑约束和访问模式。对于一般用法,我强烈建议您的类型表直接引用您的实体。即,实体(entityID),Name(NameID,EntityID,Name),Phone(PhoneID,EntityID,Phone),Email(EmailID,EntityID,Email)。您将有一些数据重复和一些常见的列,但编程和优化将更容易。

答案 5 :(得分:0)

方法1是最好的,但是某事物与object1,object2,object3之间的关联应该是一对一的。

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

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

答案 6 :(得分:0)

没有单一或通用的最佳实践来实现这一目标。这一切都取决于应用程序所需的访问类型。

我的建议是概述这些表的预期访问类型:

  1. 您会使用OR层,存储过程还是动态SQL?
  2. 您期望有多少记录?
  3. 不同子类之间的差异程度是多少?多少列?
  4. 您会进行汇总或其他复杂的报告吗?
  5. 您是否有报告数据仓库?
  6. 您是否经常需要在一批中处理不同子类的记录? ...
  7. 根据这些问题的答案,我们可以制定出合适的解决方案。

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

答案 7 :(得分:0)

我使用过第一种方法。在极端负荷下," Something"桌子成了瓶颈。

我采用了为我的不同对象提供模板DDL的方法,并将属性特化附加到表定义的末尾。

在数据库级别,如果我真的需要将我的不同课程表示为" Something"记录集,然后我把一个视图放在他们的顶部

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

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

如果你采用这种方法,那么你就可以避免出现“问题”的问题。导致锁定/阻塞的对象。

如果你想改变" Something"对象然后这可能很尴尬现在你有三个独立的对象,所有这些对象都需要改变它们的结构。

总结一下。选项一在大多数情况下都可以正常工作,但是在严重负载下,您可能会发现锁定阻塞,需要拆分设计。

答案 8 :(得分:0)

具有多列外键的方法1是最好的。因为这样,您可以与其他表进行预定义的连接 这使脚本更容易选择,插入和更新数据。