外键中的循环依赖:使用还是避免?

8
我的应用程序从数据库中加载大量数据到一个复杂的数据结构中。内存中的数据结构类似于数据库的结构,这意味着如果数据库包含以下表格:
- 表A,键为A1 - 表B,键为B1,其中一列是指向表A的外键 - 表C,键为C1,其中一列是指向表B的外键
那么我就有了A、B和C三个类,并且:
- B的一个数据成员(B::m_a)是指向A的指针 - C的一个数据成员(C::m_b)是指向B的指针
这意味着如果我要加载数据库,就必须按正确的顺序进行加载。如果我首先加载C,那么它会抱怨无法设置C::m_b的值,因为它应该指向的实例还没有被加载。
问题在于,如果A中也有一个列是指向其他表的外键,比如C,那么就会出现问题。
我可以通过将所有外键作为字符串加载,然后在加载完所有数据之后执行查找来解决这个问题,但由于有时我必须加载数百万条记录,我不能负担这些(虽然是临时的)字符串所需的内存。
阅读过好的设计方案(例如《大规模C++软件设计》一书)后,我认为根本不应该有循环引用的设计。例如,如果文件X.H包含Y.H,但Y.H也包含X.H,那么你可能有一个糟糕的设计;如果类X依赖于类Y,反之亦然,那么你可能有一个糟糕的设计,应该通过提取这种依赖关系并引入第三个类Z来解决,该类Z依赖于X和Y(X和Y将不再相互依赖)。
那么,在数据库设计中也采用这种设计规则是一个好主意吗?换句话说:是否要防止外键中的循环引用?
4个回答

8

从数据建模的角度来看,循环依赖并没有什么根本上的“问题”。这并不意味着模型是错误的。

不幸的是,大多数SQL数据库管理系统无法有效地实现这样的约束,因为它们不支持多表更新。通常唯一的解决方法是暂时挂起一个或多个约束(例如使用“可延迟”外键或类似功能),或通过更改模型使某些约束部分变为可选项(将其中一个引用列放入新表中)。然而,这只是对SQL一个恶劣限制的权宜之计,这并不意味着您在开始时做错了什么。


4
你需要对拥有的数据进行建模。如果数据存在循环关系(例如,每个照片都属于一个文件夹;但每个文件夹都有一张封面照片),那么在数据库中将其建模为循环关系是正确的。
我只在使用Oracle时遇到过这种情况,所以没有机会了解如何在其他数据库上实现这种关系。但对于Oracle,您可以在这里阅读我的文章:

http://www.databasesandlife.com/circular-dependencies-on-foreign-key-constraints-oracle/


1
你唯一需要循环引用的时候是在创建分层结构,比如组织树。
Table Employees
   EmployeeID   <----------|
   SupervisorEmployeeID ---|

2
你的观点过于绝对了。我可以想到更多的情况,例如,在需要指向“N集合”中最后添加的行的1:N关系中怎么办?或者像下面Adrian Smith提到的那样。当然,你可以通过一些变通方法来解决这个问题,但在你的例子中也是如此。 - NoOne

0

是的,数据库中的循环依赖关系是重新思考设计的好借口。


9
为什么?你没有为你的说法提供任何理由。 - cdmckay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接