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

时间:2010-10-08 14:25:02

标签: 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中的列也是其他表之一的外键时,让我们说C。

我可以通过将所有外键加载为字符串来解决问题,然后在加载所有数据后执行查找,但由于我有时需要加载数百万条记录,因此我无法承担这些内存(虽然是临时的)字符串。

阅读好的设计(例如“大型C ++软件设计”一书)后,在我看来,根本没有循环引用是个坏主意。 例如。如果文件X.H包含Y.H,但是Y.H也包括X.H你可能有一个糟糕的设计;如果X类依赖于Y类,反之亦然,那么你可能有一个糟糕的设计,应该通过提取这个依赖并引入第三个Z来解决,它取决于X和Y(X和Y将不再依赖于彼此)

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

4 个答案:

答案 0 :(得分:5)

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

不幸的是,大多数SQL DBMS无法有效实现此类约束,因为它们不支持多个表更新。通常,唯一的方法是临时暂停一个或多个约束(例如使用“可延迟”外键或类似功能)或通过更改模型以使约束的某些部分可选(将其中一个引用列放入新表)。这只是一个令人讨厌的SQL限制的解决方法,但是,这并不意味着你做错了什么。

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:2)

您需要循环引用的唯一时间是在创建层次结构时,例如组织树。

Table Employees
   EmployeeID   <----------|
   SupervisorEmployeeID ---|

答案 3 :(得分:1)

是的,数据库中的周期性依赖性是重新思考设计的一个很好的借口。