我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。

人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?

编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”


当前回答

我同意前面的答案,因为它们对维护数据一致性很有用。然而,Jeff Atwood几周前发表了一篇有趣的文章,讨论了规范化和一致性数据的利弊。

简而言之,在处理大量数据时,非规范化数据库可以更快;你可能不关心精确的一致性取决于应用程序,但它迫使你在处理数据时更加小心,因为DB不会。

其他回答

在我参与的一个项目中,经常存在隐式关系而不是显式关系,这样可以在同一列上连接多个表。

请看下面的表格

地址

AddressId (PK) EntityId EntityType 城市 状态 国家 等。

EntityType的值可能是Employee、Company、Customer, EntityId指的是您感兴趣的表的主键。

我真的不认为这是最好的方法,但它对这个项目有效。

在DB2中,如果使用mqt(物化查询表),优化器需要外键约束才能为任何给定的查询选择正确的计划。由于元数据包含基数信息,优化器会大量使用元数据来决定是否使用MQT。

使用外键的原因:

you won't get Orphaned Rows you can get nice "on delete cascade" behavior, automatically cleaning up tables knowing about the relationships between tables in the database helps the Optimizer plan your queries for most efficient execution, since it is able to get better estimates on join cardinality. FKs give a pretty big hint on what statistics are most important to collect on the database, which in turn leads to better performance they enable all kinds of auto-generated support -- ORMs can generate themselves, visualization tools will be able to create nice schema layouts for you, etc. someone new to the project will get into the flow of things faster since otherwise implicit relationships are explicitly documented

不使用外键的原因:

you are making the DB work extra on every CRUD operation because it has to check FK consistency. This can be a big cost if you have a lot of churn by enforcing relationships, FKs specify an order in which you have to add/delete things, which can lead to refusal by the DB to do what you want. (Granted, in such cases, what you are trying to do is create an Orphaned Row, and that's not usually a good thing). This is especially painful when you are doing large batch updates, and you load up one table before another, with the second table creating consistent state (but should you be doing that sort of thing if there is a possibility that the second load fails and your database is now inconsistent?). sometimes you know beforehand your data is going to be dirty, you accept that, and you want the DB to accept it you are just being lazy :-)

我认为(我不确定!)大多数已建立的数据库都提供了一种指定外键的方法,这种方法不是强制的,只是一些元数据。由于不强制执行消除了不使用fk的所有理由,如果第二部分中的任何理由适用,您可能应该走那条路。

我还认为外键在大多数数据库中是必要的。唯一的缺点(除了强制一致性带来的性能损失之外)是使用外键允许人们编写假定存在功能外键的代码。这绝不应该被允许。

例如,我看到有人编写了一些代码,将插入插入引用表中,然后尝试将插入插入引用表中,而不验证第一次插入是否成功。如果稍后删除外键,则会导致数据库不一致。

您也不能在更新或删除时假设特定的行为。无论是否存在外键,您仍然需要编写代码来执行您想要的操作。如果您假设删除是级联的,但实际上它们不是级联的,那么您的删除将失败。如果您假定对引用列的更新被传播到引用行,但实际上没有,那么您的更新将失败。出于编写代码的目的,最好不要使用这些特性。

如果打开了这些特性,那么您的代码无论如何都会模仿它们,并且会损失一些性能。

所以,总结....如果需要一致的数据库,外键是必不可少的。在您编写的代码中,永远不应假定外键存在或起作用。

我可以看到使用外键的一些原因(有人提到,孤立行很烦人),但我也从不使用它们。对于一个相对正常的DB模式,我不认为它们是100%需要的。约束是好的,但我认为通过软件来实施约束是更好的方法。

亚历克斯