在这种情况下必须使用外键(innoDB / mysql)

时间:2009-11-27 16:27:34

标签: performance foreign-keys primary-key innodb

我最近将我的整个数据库从myisam迁移到了innodb。我对这一切都很新,所以我对使用外键有疑问。

假设我有两个表:用户,消息。

的用户

id (pr_key)
name

的消息

id (pr_key)
user_id
message

id字段都是自动递增的。

所以现在在我的查询中我已经加入了这两个表。是否仍然需要在这里放置一个外键,我实际上没有看到一点。它是否具有性能优势。

如果我选择在此处输入外键,我假设我必须将消息的pr_key设为id和user_id。

  

添加其他prim_key不仅会占用更多空间,而且会导致性能降低。

     

现在,如果表有两个pr_keys,并且我只查询其中一个,那么我是否仍然具有相同的性能优势。或者我是否需要明确使用这两个键。

我知道在这个例子中我会搜索user_id所以无论如何索引这个都可能很聪明。但是,如果该字段是没有搜索的字段,该怎么办?是否仍然可以在此字段上放置多个主键,仅用于外来的hey关系。

谢谢!

2 个答案:

答案 0 :(得分:3)

它具有 数据完整性 的好处。

当用户表中没有id = 1234的用户时,它将阻止应用程序代码在消息表中输入1234的user_id。当用户在消息表中有任何消息时,它将阻止应用程序删除用户。

PK的名称不必与引用子表中的FK名称匹配。

“如果我选择在此处输入外键,我假设我必须将消息的pr_key同时设为id和user_id。”

<强> NO 即可。您不更改消息表中的键,只需在消息表中的User_Id列上建立外键(FK)约束,该约束引用(指向)users表上的id列。消息中不需要额外的PK,并且由于PK已经是唯一的(你不能有两条带有相同messageId的消息),因此id和user_id上的PK都不能再增加唯一性。)

这里的底线是,您可能对主键和外键实际上是什么有一个基本的误解。

  • PK是对行唯一性的约束,它需要索引。
  • FK是对列值的约束(它要求值在某些其他引用的表中作为PK值存在)它需要索引。

@Noah,请查看此Other SO question

答案 1 :(得分:2)

无论是否在消息(user_id)上建立正式的FOREIGN KEY规则,简单的事实是这是一个外键关系。

首先,请记住,表上正确的主键应足以唯一标识表中的每条记录。考虑到每个消息已经包含id字段,您不需要也不特别想将user_id包装到消息表的主键中。

其次,正如Charles已经声明在消息(user_id)上声明一个FOREIGN KEY,REFERENCES用户(id)将允许您确保数据的完整性。使用外键约束,您可以指定删除在users表中具有相应记录的users表中的记录时要执行的操作。您的选择是ON DELETE CASCADE(删除此用户记录的所有子记录),ON DELETE RESTRICT(不允许删除用户在消息表中有记录),ON DELETE NO ACTION(忽略删除操作) ,ON DELETE SET NULL(保留子记录但将user_id字段设置为NULL)。

根据具体情况,每个选项都是合适的,但最重要的是你可以防止从子表到父表的意外空指针。

第三,建立FOREIGN KEY关系将提供性能提升,因为这将在与users表上的PRIMARY KEY对应的消息(user_id)上生成INDEX。在执行连接这些字段的任何查询时,您将看到与未建立FOREIGN KEY相比,必须查询以返回子记录的记录数量大幅减少。

@Charles Bretana - 您链接的问题特定于Microsoft SQL Server。这里的问题是关于MySQL / InnoDB。

我建议您查看InnoDB Foreign Key Constraints的文档。

  

InnoDB需要外国索引   键和引用键,以便   外键检查可以快速而不是   需要进行表扫描。在里面   引用表,必须有一个   索引所在的外键列   被列为第一列   同样的顺序。创建了这样的索引   在引用表上自动   如果它不存在。 (这是在   与一些旧版本形成鲜明对比   必须创建哪些索引   明确地或创造外国的   关键约束会失败。)   index_name,如果给定,则用作   如前所述。