我最近将我的整个数据库从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关系。
谢谢!
答案 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都不能再增加唯一性。)
这里的底线是,您可能对主键和外键实际上是什么有一个基本的误解。
@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,如果给定,则用作 如前所述。