MySQL – 一对一的关系?

现在我知道关于一对一关系有一些答案,但他们都没有回答我的问题,所以请在表决之前阅读这个:)

我试图在MySQL数据库中实现一对一的关系。 例如让我说我有用户表和帐户表。 而且我想确定有用户只能有一个帐户。 而且每个用户只能有一个帐户。

我发现了两个解决scheme,但不知道该用什么,还有其他的select。

第一个scheme

DROP DATABASE IF EXISTS test; CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci; USE test; CREATE TABLE users( id INT NOT NULL AUTO_INCREMENT, user_name VARCHAR(45) NOT NULL, PRIMARY KEY(id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; CREATE TABLE accounts( id INT NOT NULL AUTO_INCREMENT, account_name VARCHAR(45) NOT NULL, user_id INT UNIQUE, PRIMARY KEY(id), FOREIGN KEY(user_id) REFERENCES users(id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; 

在这个例子中,我定义了用户中指向主键的帐户中的外键。 然后我做外键独特,所以不能有两个相同的帐户用户。 要连接表,我会使用这个查询:

 SELECT * FROM users JOIN accounts ON users.id = accounts.user_id; 

解决scheme二

 DROP DATABASE IF EXISTS test; CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci; USE test; CREATE TABLE users( id INT NOT NULL AUTO_INCREMENT, user_name VARCHAR(45) NOT NULL, PRIMARY KEY(id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; CREATE TABLE accounts( id INT NOT NULL AUTO_INCREMENT, account_name VARCHAR(45) NOT NULL, PRIMARY KEY(id), FOREIGN KEY(id) REFERENCES users(id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; 

在这个例子中,我创build了从主键指向另一个表中的主键的外键。 由于主键默认情况下是唯一的,这使得这种关系一对一。 要连接表,我可以使用这个:

 SELECT * FROM users JOIN accounts ON users.id = accounts.id; 

现在的问题是:

  • 在MySQL中创build一对一关系的最佳方式是什么?
  • 除了这两个之外还有其他解决scheme吗?

我正在使用MySQL Workbench,当我在EER图中deviseOne To One关系,并让MySQL Workbench产生SQL代码时,我得到了一对多的关系:S这让我感到困惑:S

如果我将这些解决scheme中的任何一个导入到MySQL Workbench EER图表中,则它将关系识别为一对多:这也是令人困惑的。

那么,在DDL中定义One to One关系的最好方法是什么? 有什么select来实现这一目标?

谢谢!!

由于主键默认情况下是唯一的,这使得这种关系一对一。

不,这使关系“一个零或一个”。 这是你真正需要的吗?

如果 ,那么你的“第二个解决scheme”更好:

  • 它更简单,
  • 占用更less的存储空间1 (因此使caching“更大”)
  • 他less维护2的索引,这有利于数据操纵,
  • 和(因为您使用的是InnoDB)自然地将数据集群在一起,因此靠近在一起的用户也将他们的帐户紧密地存储在一起,这可能有利于caching局部性和某些types的范围扫描。

顺便说一句,你需要使accounts.id一个普通的整数(不自动增量)这个工作。

如果不是 ,请看下面…

在MySQL中创build一对一关系的最佳方式是什么?

那么,“最好”是一个重载词,但是“标准”解决scheme将与其他数据库相同:将两个实体(用户和帐户)放在同一个物理表中。

除了这两个之外还有其他解决scheme吗?

理论上讲,你可以在两个PK之间创build循环FK,但是这需要延迟约束来解决鸡与蛋问题,这在MySQL下是不受支持的。

如果我将这些解决scheme中的任何一个导入到MySQL Workbench EER图表中,则它将关系识别为一对多:这也是令人困惑的。

我对这个特定的build模工具没有太多的实践经验,但是我猜这是因为它是“一对多”,其中“许多”方面是独一无二的。 请记住,“许多”并不意味着“一个或多个”,这意味着“0或许多”,所以“封顶”版本的意思是“0或1”。


1不仅在附加字段的存储费用中,而且在二级索引中。 而且,由于您使用的是总是将表集群化的 InnoDB,所以要注意,二级索引在集群表中比在堆表中更昂贵。

2 InnoDB 需要外键索引 。

您的第一个方法在帐户表中创build两个候选键: iduser_id

因此,我build议第二种方法,即使用外键作为主键。 这个:

  • 使用一个较less的列
  • 允许您唯一标识每一行
  • 允许您将帐户与用户进行匹配

那么下面的方法呢?

  1. 创build表用户

     CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
  2. user_idaccount_id上创build具有唯一索引的表帐户,其中包含与用户/帐户的外键关系以及user_id and account_id上的主键

     CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
  3. 创build表user2account

     CREATE TABLE `user2account` ( `user_id` int(11) NOT NULL, `account_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`account_id`), UNIQUE KEY `FK_account_idx` (`account_id`), UNIQUE KEY `FK_user_idx` (`user_id`), CONSTRAINT `FK_account` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`), CONSTRAINT `FK_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

虽然这个解决scheme在数据库中占有最大的空间,但是有一些优势。

  • 把FK_Key放在用户表或账户表中,我希望是一对多的(用户有很多帐户…)
  • 虽然此user2account方法主要用于定义多对多关系,但在user_idaccount_id上添加UNIQUE约束将会阻止创build除一对一关系外的其他内容。

我在这个解决scheme中看到的主要优点是可以将工作分成不同的代码层或公司的部门

  • 部门A负责创build用户,即使没有账户表的写入权限,这也是可能的
  • 部门B负责创build帐户,即使没有对用户表的写入权限也是如此
  • 部门C负责创build映射,即使没有对用户或帐户表的写入许可,这也是可能的
  • 一旦C部分创build了一个映射,用户和帐户都不能被A部分或B部分删除,而不要求C部分先删除映射。