You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

一对多关系数据库建模:为何多数人选外键而非复合键?

一对多关系建模:为何多数开发者选择“有缺陷”的方案?

我有一个疑问:为何多数人在关系型数据库中建模“一对多”关系时,会选择一种看似有缺陷的方式?

为简化说明,我们以一款事务型应用为例:

  • 界面1:显示订单列表
  • 界面2:显示单个订单的0至N个订单项

这是众多处理文档与工作流的事务型应用的典型基础场景。数据库建模至少有两种主要方案,以下以MariaDB为例进行说明。

方案1:仅通过外键关联的独立数据库实体

该方案下:

CREATE TABLE `order` (
  id_order INT,
  orderfield1 VARCHAR(255),
  PRIMARY KEY (id_order)
);

表结构如下:

+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| id_order    | int(11)      | NO   | PRI | NULL    |       |
| orderfield1 | varchar(255) | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+

以及订单项表:

CREATE TABLE `orderitem` (
  id_order INT,
  id_item INT, 
  orderitemfield1 VARCHAR(255),
  PRIMARY KEY (id_item),
  FOREIGN KEY (`id_order`) REFERENCES `order`(`id_order`) 
);

表结构如下:

+-----------------+--------------+------+-----+---------+-------+
| Field           | Type         | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| id_order        | int(11)      | YES  | MUL | NULL    |       |
| id_item         | int(11)      | NO   | PRI | NULL    |       |
| orderitemfield1 | varchar(255) | YES  |     | NULL    |       |
+-----------------+--------------+------+-----+---------+-------+

方案2:“从属”实体采用复合主键

该方案下,订单表与方案1一致:

CREATE TABLE `order` (
  id_order INT,
  orderfield1 VARCHAR(255),
  PRIMARY KEY (id_order)
);

表结构如下:

+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| id_order    | int(11)      | NO   | PRI | NULL    |       |
| orderfield1 | varchar(255) | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+

订单项表采用复合主键:

CREATE TABLE `orderitem` (
  id_order INT,
  id_item INT,
  orderitemfield1 VARCHAR(255),
  PRIMARY KEY (id_order, id_item),
  FOREIGN KEY (`id_order`) REFERENCES `order`(`id_order`) 
);

表结构如下:

+-----------------+--------------+------+-----+---------+-------+
| Field           | Type         | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| id_order        | int(11)      | NO   | PRI | NULL    |       |
| id_item         | int(11)      | NO   | PRI | NULL    |       |
| orderitemfield1 | varchar(255) | YES  |     | NULL    |       |
+-----------------+--------------+------+-----+---------+-------+

我的分析与观点

实际业务场景是选择方案1或方案2的唯一依据。我认为“一对多”(实体A-实体B)关系可对应两种业务需求:

  • 实体B无法脱离实体A存在(例如:订单的订单项/购物车、帖子的评论等)
  • 实体B可脱离实体A存在(例如:创建/更新单个文档的0至N个用户等)

在建模“实体B无法脱离实体A存在”的一对多关系时,方案2是多数业务场景下的最优选择,原因如下:
假设orderitem表包含10亿条记录,用户要查看某一订单文档。方案1中,为提升性能需在非主键的id_order列创建索引,除10亿行的表外,还会新增一个10亿规模的B树索引实体,占用额外存储资源。此外,应用服务器的错误可能导致orderitem表中出现违反业务规则的记录。

而方案2中,复合主键的id_order本身即可作为索引,以log(n)时间获取相关实体B记录,无需额外占用存储资源。

不过,在建模“实体B可脱离实体A存在”的一对多关系时,若多数查询仅针对实体B,方案1可能是最优选择。

请问我的上述分析是否正确?若正确,为何多数数据库开发者会脱离业务实际,选择外键方案而非复合键方案?多数ORM也会大力推崇外键方案,无论功能需求与性能考量。

内容的提问来源于stack exchange,提问作者ChristopheN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:17:28