我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。
人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?
编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”
我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。
人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?
编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”
当前回答
我同意前面的答案,因为它们对维护数据一致性很有用。然而,Jeff Atwood几周前发表了一篇有趣的文章,讨论了规范化和一致性数据的利弊。
简而言之,在处理大量数据时,非规范化数据库可以更快;你可能不关心精确的一致性取决于应用程序,但它迫使你在处理数据时更加小心,因为DB不会。
其他回答
更大的问题是:你会戴着眼罩开车吗?如果你开发一个没有参考约束的系统就是这样。请记住,业务需求会改变,应用程序设计会改变,代码中相应的逻辑假设也会改变,逻辑本身也会被重构,等等。一般来说,数据库中的约束是在当代逻辑假设下放置的,对于特定的逻辑断言和假设集似乎是正确的。
在应用程序的整个生命周期中,引用检查和数据检查约束控制通过应用程序收集的数据,特别是当新需求驱动逻辑应用程序更改时。
从实时事务处理系统的角度来看,外键本身不会“提高性能”,也不会显著“降低性能”。然而,在大容量“批处理”系统中,约束检查存在一个聚合代价。这就是实时和批量事务处理的区别;批处理——通过约束检查,按顺序处理的批处理的总成本会对性能造成影响。
在一个设计良好的系统中,数据一致性检查将在处理批处理之前完成(然而,这里也有相关的成本);因此,加载时不需要外键约束检查。事实上,所有的约束,包括外键,都应该暂时禁用,直到批处理完成。
QUERY性能——如果表是在外键上连接的,那么要认识到外键列不是索引的事实(尽管根据定义,各自的主键是索引的)。通过索引一个外键,也就是索引任何键,在索引上连接表有助于提高性能,而不是通过连接一个带外键约束的非索引键。
Changing subjects, if a database is just supporting website display/rendering content/etc and recording clicks, then a database with full constraints on all tables is over kill for such purposes. Think about it. Most websites don’t even use a database for such. For similar requirements, where data is just being recorded and not referenced per say, use an in-memory database, which does not have constraints. This doesn’t mean that there is no data model, yes logical model, but no physical data model.
如果您绝对确信底层数据库系统将来不会改变,我将使用外键来确保数据完整性。
但在现实生活中,还有一个完全不使用外键的很好的理由:
您正在开发一个产品,该产品应该支持不同的数据库系统。
如果您正在使用实体框架(Entity Framework),该框架能够连接到许多不同的数据库系统,那么您可能还希望支持“开源免费”的无服务器数据库。并非所有这些数据库都支持外键规则(更新、删除行……)。
这会导致不同的问题:
1)。在创建或更新数据库结构时,可能会遇到错误。可能只有无声错误,因为数据库系统忽略了外键。
2)。如果依赖于外键,则可能在业务逻辑中较少甚至不进行数据完整性检查。现在,如果新的数据库系统不支持这些外键规则,或者只是以不同的方式运行,那么您必须重写业务逻辑。
您可能会问:谁需要不同的数据库系统?当然,不是每个人都能负担得起或想要在他的机器上安装一个完整的SQL-Server。这是软件,需要维护。其他人已经在其他一些DB系统上投入了时间和金钱。无服务器数据库非常适合只有一台机器上的小客户。
没有人知道,所有这些DB系统是如何运行的,但是您的业务逻辑,包括完整性检查,总是保持不变的。
有一个很好的理由不使用它们:如果你不了解它们的作用或如何使用它们。
在错误的情况下,外键约束可能导致事故的瀑布式复制。如果有人删除了错误的记录,恢复它可能会成为一项艰巨的任务。
同样,相反,当您需要删除某些内容时,如果设计不当,约束可能会导致各种锁阻止您的操作。
使用外键的原因:
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的所有理由,如果第二部分中的任何理由适用,您可能应该走那条路。
使用外键的其他原因: —可以更好地重用数据库
不使用外键的其他原因: —您试图通过减少重用来锁定客户。