我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。
人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?
编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”
我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。
人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?
编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”
当前回答
我一直认为不用它们是懒惰的表现。我被教导应该一直这样做。但后来,我没有听乔尔的讨论。他也许有充分的理由,我不知道。
其他回答
数据结构设计的一个好的原则是确保表或对象的每个属性都服从于一个很好理解的约束。这很重要,因为如果您或您的程序可以依赖数据库中的有效数据,那么就不太可能出现由坏数据引起的程序缺陷。您还可以花费更少的时间来编写处理错误条件的代码,并且更有可能预先编写错误处理代码。
在许多情况下,这些约束可以在编译时定义,在这种情况下,您可以编写一个筛选器来确保属性总是在范围内,或者尝试保存属性失败。
然而,在许多情况下,这些约束可以在运行时更改。例如,您可能有一个“cars”表,其属性为“colour”,初始值为“red”、“green”和“blue”。在程序执行期间,可以将有效的颜色添加到初始列表中,并且添加的新“汽车”可以采用最新颜色列表中的任何颜色。此外,您通常希望这个更新的颜色列表在程序重新启动后仍然有效。
To answer your question, it turns out that if you have a requirement for data constraint that can change at run-time, and those changes must survive a program restart, foreign keys are the simplest and most concise solution to the problem. The development cost is the addition of one table (e.g. "colours", a foreign key constraint to the "cars" table, and an index), and the run-time cost is the extra table lookup for the up-to-date colours to validate the data, and this run-time cost is usually mitigated by indexing and caching.
如果您不使用外键来满足这些需求,那么您必须编写软件来管理列表、查找有效的条目、将其保存到磁盘、如果列表很大的话有效地组织数据、确保对列表的任何更新都不会破坏列表文件、在有多个读取器和/或写入器的情况下提供对列表的串行访问,等等。例如,你需要实现大量的RDBMS功能。
有一个很好的理由不使用它们:如果你不了解它们的作用或如何使用它们。
在错误的情况下,外键约束可能导致事故的瀑布式复制。如果有人删除了错误的记录,恢复它可能会成为一项艰巨的任务。
同样,相反,当您需要删除某些内容时,如果设计不当,约束可能会导致各种锁阻止您的操作。
在DB2中,如果使用mqt(物化查询表),优化器需要外键约束才能为任何给定的查询选择正确的计划。由于元数据包含基数信息,优化器会大量使用元数据来决定是否使用MQT。
像许多事情一样,这是一种权衡。这是一个你想在哪里进行验证数据完整性的工作的问题:
(1)使用外键(单点配置为一个表,功能已经实现,经过测试,证明有效)
(2)把它留给数据库的用户(可能多个用户/应用程序更新同一个表),这意味着更多潜在的故障点和测试的复杂性)。
数据库执行(2)更有效,使用(1)更容易维护,风险更小。
使用外键的原因:
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的所有理由,如果第二部分中的任何理由适用,您可能应该走那条路。