使用生成的主键引用表
Posted
技术标签:
【中文标题】使用生成的主键引用表【英文标题】:Referencing table with generated primary keys 【发布时间】:2015-04-29 16:36:16 【问题描述】:我正在尝试增加我的 MySQL 数据库架构的约束,为每个表添加外键约束。
表 1:用户
+---------+----------+-------------
| id | username | Other fields
+---------+----------+-------------
| 1 | John |
| 2 | Mark |
+---------+----------+-------------
id
INT(11) UNSIGNED NOT NULL AUTO_INCREMENT用户名` VARCHAR(50) NOT NULL
主键 (
id
)
表 2:DISKS(这与 USERS 具有一对多关系)
+---------+----------+-----------+-------------
| id | id_user | disk_name | Other fields
+---------+----------+-----------+-------------
| 1 | 1 | disk A |
| 2 | 2 | disk B |
+---------+----------+-----------+-------------
id
INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
id_user
INT(11) 非空,主键 (
id
,id_user
) 索引fk_disks_idx
(id
ASC)约束
fk_disks
外键 (
id
)参考
database
.USERS
(id
)不删除任何操作
更新无操作)
表 3:FILES(这与 DISKS 具有一对多关系)
+---------+----------+----------+-----------+-------------
| id | id_disk | id_user | file_name | Other fields
+---------+----------+----------+-----------+-------------
| 1 | 1 | 1 | |
| 2 | 2 | 2 | |
+---------+----------+----------+-----------+-------------
id
INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
id_user
INT(11) 非空
id_disk
INT(11) 非空主键 (
id
,id_disk
,id_user
) 索引fk_files_idx
(id
ASC,id_user
ASC)约束
fk_files
外键(
id_disk
、id_user
、id_user
)参考
database
.DISKS
(id
)不删除任何操作
更新无操作)
表 2:FILES_ON_NAS(这与 FILES 具有一对一关系)
+-------+----------+----------+----------+-----------+-------------
| id | id_files | id_user | id_disk | file_name | Other fields
+-------+----------+----------+----------+-----------+-------------
| 1 | 1 | 1 | 1 | |
| 2 | 1 | 2 | 2 | |
+-------+----------+----------+----------+-----------+-------------
id
INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
id_files
INT(11) 非空,
id_user
INT(11) 非空,
id_disk
INT(11) 非空,主键 (
id
,id_files
,id_user
,id_disk
) 索引fk_files_on_nas_idx
(id
ASC)约束
fk_files_on_nas
外键(
id_files
,id_user
,id_disk
)参考
database
.FILES
(id
,id_user
,id_disk
)不删除任何操作
更新无操作)
问题:
如您所见,我在级联中引用的表越多,我得到的主键就越多。如何设计数据库以避免复制主键,从而避免数据重复?我应该删除每个表的自动递增键吗?这是一个好习惯吗?
谢谢
【问题讨论】:
【参考方案1】:磁盘的 ID 足以唯一标识磁盘。所以没有理由将用户的 ID 包含在磁盘的主键中。这甚至是一个非常糟糕的主意,因为这意味着如果磁盘的用户发生变化,您将需要修改主键。
文件也一样。文件 ID 唯一标识一个文件。所以没有理由将磁盘 ID 添加到文件的主键中。
【讨论】:
我完全同意你的看法。我问这个问题的原因是因为当我使用 mysql Workbenck(EER 模型部分)创建生成 sql 文件的一对多关系时,软件将所有主键放入表中。我试图删除不必要的主键,但引擎不允许将模型转发到数据库中 我不知道 MySQL 工作台是如何工作的。我一般使用 PostgreSQL,我直接使用 SQL 创建表。 我过去使用过 MySQL Workbench,但我不记得遇到过这个问题......但我现在使用的是 SQLYog,所以我真的不知道。 您可能没有正确执行此操作,因为它没有理由从这样的外键中生成主键。 我按照您的最佳实践解决了我的问题。我在 gedit 文档中手动删除了这些字段,并将其粘贴到 mysql 控制台后,我运行脚本没有问题。软件有些奇怪,导致我创建了不必要的主键【参考方案2】:我强烈建议不要删除自动递增的键。
但是你不需要每次都创建一个新的主键:
如果您希望多个用户共享一个磁盘,只需在 USERS 中放入id_disk
的外键
如果您希望一个用户可以拥有多个磁盘,则在 DISKS 中放置一个 外键 id_user
。
只有在遇到 多对多 关系时才使用这样的主键。在这种情况下,您需要创建一个新表来连接两个表;将两个表的主键作为外键,形成一个耦合的主键,就像你做的那样。
【讨论】:
非常感谢,这很有帮助【参考方案3】:您可能想了解一下Database Normalization。在您的情况下,我会将 surrogate key id
设为表中唯一的主键。比如:
create table users (
id integer not null auto_increment,
username varchar(50),
...,
primary key (id)
);
create table disks (
id integer not null auto_increment,
user_id integer,
diskname varchar(50),
....,
primary key (id),
foreign key (user_id) references users (id)
);
对于files
,您将不得不回答这个问题:文件所有权是直接依赖于文件,还是传递地依赖于磁盘所有权,还是所有权独立?杰克拥有的磁盘上的约翰拥有的文件?对我来说似乎没问题,但您的域可能有不同的规则。在这种情况下,请从 files 表中删除 user_id(否则您的数据库将不在 Third normal form 中)。
create table files (
id integer not null auto_increment,
disk_id integer,
user_id integer, -- you have to decide whether this is necessary
filename varchar(50),
....,
primary key (id),
foreign key (disk_id) references disks (id),
foreign key (user_id) references users (id)
);
【讨论】:
非常感谢您的帮助以上是关于使用生成的主键引用表的主要内容,如果未能解决你的问题,请参考以下文章