我有很多像这样的表:
CREATE TABLE `name` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user` INT(11) UNSIGNED NOT NULL REFERENCES users (`id`),
`user2` INT(11) UNSIGNED NOT NULL REFERENCES users (`id`),
`data` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
我想知道这个references users
是否是一个很好的选择我应该把它留空以加快性能和改进?
答案 0 :(得分:2)
使用外键与性能无关。实际上,它可以添加一点开销,因为对表的任何插入或更新都需要验证引用表中是否存在该值。但实际上,这并不比更新索引更多。
使用外键的原因不是性能,而是用于确保数据完整性。如果没有外键,对数据库的任何更新都可能会删除users
中的父行,即使name
中有行引用它也是如此。没有外键约束,只有您的编码习惯才能保持数据的完整性。使用外键约束时,如果存在其他行,则删除users
中的行将返回错误。
这可能听起来像是个好主意,但有不同意见。约束可能会限制您需要执行的某些工作。例如,我已经与那些在需要清理格式错误的数据时发现限制因素的开发人员进行了交谈。锁定行为可能会让您感到惊讶:例如,如果更新name
中的从属行,则会在users
中引用的行上创建锁定。
/* this also implicitly puts a shared lock on `users` where id = 1234 */
UPDATE name SET ... WHERE user = 1234;
不幸的是,MySQL的InnoDB存储引擎不支持您显示的语法,您可以在每个列定义中声明REFERENCES
子句。尽管这是标准的SQL,但它在MySQL中无法识别。
你会发现以这种方式定义外键是没有错误的,但是它会无声地忽略请求,并且不会实现约束。
InnoDB仅支持表级外键的语法:
CREATE TABLE `name` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user` INT(11) UNSIGNED NOT NULL,
`user2` INT(11) UNSIGNED NOT NULL,
`data` datetime NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`user`) REFERENCES users (`id`),
FOREIGN KEY (`user2`) REFERENCES users (`id`)
) ENGINE=InnoDB;
最终结果与数据存储方式和性能影响相同。唯一的区别在于用于定义外键约束的语法。