首页 > 解决方案 > 在我的所有表格中添加或不添加引用?

问题描述

我有很多这样的表:

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是否是一个不错的选择,我应该将其留空以加快性能和改进吗?

标签: mysqlforeign-keys

解决方案


使用外键与性能关系不大。事实上,它可能会增加一点开销,因为对表的任何插入或更新都需要验证该值是否存在于引用的表中。但在实践中,这并不比更新索引多多少开销。

使用外键的原因不是性能,而是为了确保数据完整性。如果没有外键,对数据库的任何更新都可能会删除父行,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;

在数据存储方式和性能影响方面,最终结果是相同的。唯一的区别在于用于定义外键约束的语法。


推荐阅读