在MySQL中是否使用外键?

6

我已经使用MySQL数据库编码了几年,但从未使用过外键。现在我明白了,一个外键就像是一个表中的ID对应另一个表的主键。我在我的网站上有一个用户表,大约有10个其他表都与我的用户表的主键相对应-但它们没有设置为外键。

如果这10个其他表没有外键,我会错过什么?我想说,据我所知,它们基本上就是一个外键,只是在数据库中没有保存/分配该值。

这里还有其他好处吗?

我也意识到主键不能为null,但外键可以为null。在我的情况下,这永远不会成为问题,因为我的用户表已经被创建,当一个新用户被添加到我的用户表时,我会将他们适当的条目添加到其他10个表中。


5
我在这里看到了很多答案中都提到了“你可以在代码中自己完成这个操作”,但这是一个严重的误导。我无法计算出有多少数据库在数月甚至数年的时间内变成了无效数据的混乱。毫无例外,如果在架构中正确实施了引用完整性,每个数据库都将是完美干净的。外键不是可选项——它们是良好数据库设计的关键组成部分。 - Nicholas Knight
5个回答

6

添加外键总是一个好主意 - 至少我从未见过不使用它们的充分理由。

  • 强制引用完整性(如果存在子级,则无法删除父级,无法插入孤儿或具有无效父ID的子级)
  • 作为索引工作
  • 使用外键,无论数据如何访问,无论是通过应用程序、自动化流程还是没有咖啡因的终端用户,规则都得到统一执行。

使用外键时要谨慎。 - Pegasus

3

FOREIGN KEY有两个作用:

  • 它确保您的关系始终保持一致,但会增加一些检查开销。
  • 它(有争议地)简化了级联更新和删除。

在大多数情况下,可以使用其他工具更有效地实现此功能。


1
在这里我不同意。你假设总会有一个额外的层面来服务于数据库已经拥有的目的。我认为这是一种现代化的方法,但仍然认为它很糟糕。 - Jan Zyka
@Jan:通常用于此的层称为存储过程,它并不是“覆盖”DB。外键的主要缺点是它们的逐行实现,如果您需要定期进行大量更新,则会影响性能。 - Quassnoi
那么,您会为每个表创建类似于“before insert”触发器来强制执行约束吗?这样真的更有效吗?只是问问,不是说它不行。我真的很好奇。因为您可以创建存储过程的API,用于插入/更新数据,但这是否100%安全?如果有人直接调用插入操作会怎么样? - Jan Zyka
@Jan:我创建了一个存储过程,它可以处理来自表格的插入、更新和删除操作(实际上,我有一个脚本,它可以从表格定义中创建一个默认的存储过程)。这些存储过程接受一个集合作为输入(除了MySQL之外的所有主要引擎都支持),与单个插入相比,这显然更加高效。因为表格上不授予INSERT权限,所以无法直接调用INSERT语句,只能通过执行存储过程来实现。性能优势只在大规模更新时才明显,但是我早已经开发出了这种方法,并且即使针对纯粹的OLTP应用程序也使用这种方法。 - Quassnoi
如果是这种情况,我同意你的看法。我会点赞并撤回我的第一个不同意评论。感谢您澄清,从您的回答中并不那么明显 :) - Jan Zyka

1

使用外键可以:

  • 确保只有有效的 user_id 被放入这些字段中
  • 更容易地使用级联删除
  • 无需手动在这些字段上定义索引(innodb)

0
你所缺少的是强制引用完整性(即,如果你的其他表中有user_id为27,则用户表中必须有一个ID为27的记录),以及自动级联更新和删除的能力(即,如果你删除用户27,则其他表中相应的行也会被自动删除等)。
在我看来,这并不值得。我完全有能力让我的代码处理引用完整性,并且处理外键是一件非常繁琐的维护工作。

1
目前,当用户删除帐户时,我的代码会从其他10多个表中删除,您是说这一切都可以自动化吗?我更好奇的是您提到的更新,那会做什么? - JasonDavis
8
@chaos:我相信你的代码在实施引用完整性方面总是无可挑剔的,但那些访问同一数据库的其他人编写的代码呢?或者在查询工具中运行的即席查询呢?数据库实施引用完整性的重点在于即使客户端有误,它也能保持一致性。 - Bill Karwin

0
在某些数据库中(不确定MySQL是否包括在内),FOREIGN KEY会自动创建索引,从而加快外键的连接和查询速度。此外,还有级联删除、参照完整性等已经提到的好处。

在MySQL中定义外键基本上是为了设置1)索引2)约束条件(实际的fkey)的别名,因此,是的,您将获得一个索引。 - chaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接