我记得在播客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。

Quite often we receive the errors with FK constraints Cannot add or update a child row: a foreign key constraint fails Suppose there are two tables inventory_source and contract_lines, and we are referring inventory_source_id in contract_lines from inventory_source and suppose we want to delete record from inventory_source and the record is already present in contract_lines or we want to delete the PK column from Base table, we get errors for FK constraints, we can avoid it using the steps jotted below.

CREATE TABLE inventory_source (
inventory_source_id int(11) NOT NULL AUTO_INCREMENT,
display_name varchar(40) NOT NULL,
state_id int(11) NOT NULL,
PRIMARY KEY (inventory_source_id),
KEY state_id (state_id),
CONSTRAINT ba_inventory_source_state_fk FOREIGN KEY (state_id) REFERENCES   ba_state (state_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE contract_lines(
contract_line_id int(11) NOT NULL AUTO_INCREMENT,
inventory_source_id int(11) NULL ,
PRIMARY KEY (contract_line_id),
UNIQUE KEY contract_line_id (contract_line_id),
KEY AI_contract_line_id (contract_line_id),
KEY contract_lines_inventory_source_fk (inventory_source_id),
CONSTRAINT contract_lines_inventory_source_fk FOREIGN KEY       (inventory_source_id) REFERENCES ba_inventory_source (inventory_source_id)
) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8 ;

我们可以采用以下步骤克服它:-

Delete or update the row from the inventory_source will automatically delete or update the matching rows in the contract_lines table and this is known as cascade delete or update. Another way of doing it is setting the column i.e inventory_source_id in the contract_lines table to NULL, when a record corresponding to it is deleted in the inventory_source table. We can restrict the parent table for delete or update in other words one can reject the delete or update operation for the inventory_source table. Attempt to delete or update a primary key value will not be permitted to proceed if there is a related foreign key value in the referenced table.

我一直认为不用它们是懒惰的表现。我被教导应该一直这样做。但后来,我没有听乔尔的讨论。他也许有充分的理由,我不知道。

这是一个教养问题。如果在您的教育或职业生涯中,您曾花时间维护数据库(或与有才华的人密切合作),那么实体和关系的基本原则就会在您的思维过程中根深蒂固。这些基本知识包括如何/何时/为什么在数据库中指定键(主键、外键和备选键)。这是第二天性。

If, however, you've not had such a thorough or positive experience in your past with RDBMS-related endeavors, then you've likely not been exposed to such information. Or perhaps your past includes immersion in an environment that was vociferously anti-database (e.g., "those DBAs are idiots - we few, we chosen few java/c# code slingers will save the day"), in which case you might be vehemently opposed to the arcane babblings of some dweeb telling you that FKs (and the constraints they can imply) really are important if you'd just listen.

大多数人小时候都被教育刷牙很重要。没有它你能过吗?当然,但在某个时候,如果你每顿饭后都刷牙,那么你的牙齿就会减少。如果妈妈和爸爸们有足够的责任心,把数据库设计和口腔卫生都包括在内,我们就不会有这样的对话了。: -)