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

Database design 外键中的循环依赖:使用还是避免?,database-design,foreign-keys,application-design,application-dependency,Database Design,Foreign Keys,Application Design,Application Dependency,我的应用程序将大量数据从数据库加载到复杂的数据结构中。内存中的数据结构重新编译数据库的结构,这意味着如果数据库包含以下表: 表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中还有

我的应用程序将大量数据从数据库加载到复杂的数据结构中。内存中的数据结构重新编译数据库的结构,这意味着如果数据库包含以下表:

  • 表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,反之亦然,那么您可能有一个糟糕的设计,应该通过提取此依赖项并引入第三个依赖于X和Y的类Z来解决这个问题(X和Y不再相互依赖)


将此设计规则扩展到数据库设计是一个好主意吗?换句话说:防止外键中的循环引用。

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

唯一需要循环引用的时间是在创建层次结构(如组织树)时

Table Employees
   EmployeeID   <----------|
   SupervisorEmployeeID ---|
表格雇员

EmployeeID从数据建模的角度来看,circualr依赖性没有根本上的“错误”。这并不意味着模型是错误的


不幸的是,大多数SQL DBMS无法有效地实现此类约束,因为它们不支持多个表更新。通常,唯一的解决方法是暂时挂起一个或多个约束(例如使用“可延迟”外键或类似功能),或者通过更改模型使约束的某些部分成为可选的(将一个引用列放入新表)。这只是SQL严重限制的一个解决办法,但这并不意味着一开始就做错了任何事情。

您必须对现有数据进行建模。如果数据中存在循环关系(例如,每张照片都属于一个文件夹;但每个文件夹都有一张封面照片),那么在数据库中将其建模为循环关系是正确的

我在使用Oracle时只遇到过一次这种情况,所以我没有机会了解如何在其他数据库上实现这种关系。但对于Oracle,您可以在这里阅读我的文章:


为什么?你没有为你的断言提供任何理由。你是非常绝对的。我能想到更多的例子。例如,如果一个
1:N
关系需要指向“N集合”中最后添加的行,该关系如何?或者阿德里安·史密斯(Adrian Smith)在下面提到的内容。当然,您可以绕过对它的需求,但您也可以在示例中这样做。