我应该添加传递式外键吗?


11

一个简单的例子:有一张客户表。

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

数据库中的所有其他数据都应链接到Customer,因此例如Orders

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

假设现在有一个表链接到Orders

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

我应该添加一个单独的外键ItemsCustomers

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

而是一张图片:我应该添加虚线/ FK吗?

简单示例架构


编辑:我已经将主键定义添加到表中。我想重申一下我的观点:数据库基本上是客户孤立的,作为一种正确性/安全性措施。因此,所有主键都包含customerID。


2
不,你不应该。不需要额外的FK。该约束由其他两个FK强制执行。
ypercubeᵀᴹ

@ypercube拥有冗余FK是否会影响性能?您能想到的任何优势吗?...
vektor

1
@vektor,性能方面可能因一个rdbms的不同而有所不同,但是通常,您添加的每个新FK都会对性能产生影响,因为必须对照其中一个PK / FK表中的每个插入/更新/删除操作。约束。对于较大的PK表,此性能损失可能非常严重。
Daniel Hutmacher 2014年

Answers:


6

我认为这是最初的想法。

在此处输入图片说明

首先要注意的是LineItem表上的PK具有三个属性{CustomerID, CustomerOrderNo, OdrerItemNo},而在您的示例中只有两个。

要注意的第二件事是由于id对属性使用通用名称而导致的混乱。

CustomerOrderNo理想情况下应(1,2,3 ......)为每一个客户和OrderItemNo(1,2,3 ......)每个订单。

好吧,如果可能的话,这很好,但是需要查询以查找先前的最大值,例如

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

这在高交易量环境中通常不是首选,因此常见的是将这些替换为自动增量,基本上达到了相同的目的。的确,此自动增量现在是唯一的,因此可以用作KEY,但是您可以选择将其作为的必要折中方案OrderItemNo

因此,进行一些重命名,CustomerOrderNo -> OrderNo然后OrderItemNo-> ItemNo您可能会使用此模型

在此处输入图片说明

所以现在如果您看Order以下内容是唯一的

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

请注意,该消息{CustomerID, OrderNo}会传播到LineItem作为FK。

如果您斜视一下,这很接近您的示例,但是PKs {ItemNo} and {OrderNo}只有-与示例中的两个列PK相反。

现在的问题是,为什么不简化为这样的东西?

在此处输入图片说明

很好,但是引入了PATH DEPENDENCE-您不能直接LineItem与之Customer连接,必须Order在连接中使用。


如果可能,我更喜欢第一种情况-您选择自己喜欢的。很显然,没有必要直接从FK LineItemCustomer在这三种情况。


我四处搜寻,但是我看不到“路径依赖”被广泛称为“二度传递关系”(尽管我的术语也可能是错误的)

2

“项目”不应直接引用“客户”,因为这是项目的“订单”所隐含的。因此,您根本不需要“项目”表上的“客户”列。

使用现有外键可确保该项目与客户的关系。

如果orders.id是标识列,请考虑一起删除items.customer。


1
谢谢,我没有注意到“客户”也包含在从“项目”到“订单”的第一个FK中。我已经详细阐述了我的答案。
Daniel Hutmacher 2014年

@DanielHutmacher我已经编辑了问题以包含表的主键。这解释了您在编辑中提到的怪异FK。
vektor 2014年

好的,我已经更新了答案。:)
Daniel Hutmacher 2014年

我猜想customer在所有表中都有(从而孤立数据库)是一种不寻常的方法。我必须承认,这只是我在以前的作品中看到的东西。这对您有意义吗?您以前看过这样的设计吗?
vektor 2014年

我想说它看起来像数据仓库(星型架构)方法,您想在其中故意对数据进行规范化以消除联接。或者主键可以是复合键,即客户A的第一,第二,第三订单,客户B的第一,第二订单,等等-仅在订单ID列不是唯一的情况下。
Daniel Hutmacher 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.