← 返回题目列表

MySQL 表的主键应该如何设计?

高频 中等 第 4 / 28 题 更新于 2026/07/29
MySQL主键InnoDB表设计

简化版

MySQL InnoDB 表主键建议短小、稳定、唯一、尽量递增;主键不仅用于唯一标识记录,还决定聚簇索引的数据组织方式,并会被所有二级索引引用。

详细版

InnoDB 使用聚簇索引组织表数据,通常主键索引的叶子节点保存整行数据。因此主键设计会影响插入性能、范围查询、二级索引大小和缓存效率。

常见推荐是使用 BIGINT 自增主键或趋势递增的全局 id。它短、比较快、插入位置集中,二级索引中引用成本也较低。随机 UUID 虽然全局唯一,但较长且插入随机,可能导致页分裂、索引膨胀和缓存命中下降。

当然,主键选择也要结合业务。业务字段如果会变化、较长、敏感或不稳定,不适合作为主键;可以通过唯一索引保证业务唯一性,用代理主键负责存储组织。

完整版教学

一、主键不只是唯一约束

在很多数据库知识里,主键常被理解为“唯一且非空”。在 InnoDB 中,它还承担聚簇索引键的角色。

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  order_no VARCHAR(64) UNIQUE,
  user_id BIGINT,
  amount DECIMAL(10,2)
);

这里 id 不只保证唯一,它还决定整行数据在聚簇索引 B+ 树中的组织方式。

记忆钩子:InnoDB 主键既是身份证,也是数据摆放路线。

二、为什么要短小

InnoDB 二级索引叶子节点保存的是主键值。主键越大,每个二级索引项越大。

假设表有 1000 万行、6 个二级索引:

主键类型长度对二级索引影响
BIGINT8 字节成本较低
CHAR(36) UUID36 字节每个二级索引都膨胀
VARCHAR(128)可变且更长比较和存储成本更高

这不是只多几十字节的小事。乘以千万行和多个索引后,空间、缓存命中率、IO 都会受影响。

因此主键字段应尽量短小,常见选择是 BIGINT

三、为什么要稳定

主键一旦被其他表引用或被二级索引保存,修改成本很高。业务字段如果可能变化,不适合作主键。

例如手机号:

-- 不推荐把手机号作为主键
phone VARCHAR(20) PRIMARY KEY

用户换手机号时,主键要变,关联表也要跟着变,还可能暴露隐私。更稳的设计是:

id BIGINT PRIMARY KEY,
phone VARCHAR(20),
UNIQUE KEY uk_phone(phone)

id 负责稳定标识和存储组织,phone 通过唯一索引保证业务唯一。

四、为什么尽量递增

递增主键插入时通常集中在 B+ 树右侧,页分裂较少;随机主键插入位置分散,可能在各个页中间插入,导致页分裂和数据页变动。

示意:

递增 id:1,2,3,4,5 -> 主要向右追加
随机 UUID:A7, 19, F3, 02 -> 到处插入

如果每秒插入 5000 行订单,递增主键能让写入路径更稳定。随机 UUID 的优势是分布式生成简单、难猜,但在 InnoDB 聚簇索引中会带来额外成本。

折中方案可以用趋势递增的分布式 id,如雪花算法 id。

五、代理主键和自然主键怎么选

自然主键来自业务字段,如身份证号、订单号、邮箱。代理主键是业务无关字段,如自增 id。

类型优点风险
自然主键业务含义明确可能变更、较长、敏感
代理主键稳定短小需要额外唯一约束保证业务唯一

大多数互联网业务更偏向代理主键 + 业务唯一索引。这样既保证存储层稳定,又保证业务层不重复。

例如订单表:

id BIGINT PRIMARY KEY,
order_no VARCHAR(64) NOT NULL,
UNIQUE KEY uk_order_no(order_no)

六、分布式场景要考虑生成方式

单机 MySQL 可以用自增主键,但分库分表或多写节点下,自增 id 可能冲突或难以全局有序。

常见方案:

数据库自增:简单,单库友好
号段模式:批量取号,减少数据库压力
雪花算法:趋势递增,全局生成
UUID:全局唯一,但随机且较长

如果未来要分库分表,可以提前选择全局唯一且趋势递增的 id。不要只看当前写表方便,也要看后续扩展和索引成本。

七、常见误区与追问

  • 误区:主键只要唯一就行。 InnoDB 主键还决定聚簇索引组织方式,并影响二级索引。
  • 误区:业务字段有唯一性就适合做主键。 如果字段会变化、较长或敏感,就不适合作主键。
  • 误区:UUID 做主键没有代价。 UUID 较长且随机,可能增加页分裂、索引体积和缓存压力。
  • 误区:没有主键也没关系。 InnoDB 会生成隐藏 row id,但不利于业务查询和维护。
  • 追问:为什么主键会影响二级索引? 二级索引叶子节点保存主键值,主键越大二级索引越大。
  • 追问:订单号能不能做主键? 如果订单号较长或生成规则可能变化,更建议代理主键加订单号唯一索引。

八、加强记忆

主键设计记住“四字诀”:短、稳、唯一、递增。短是为了索引空间,稳是为了关联和维护,唯一是基本要求,递增是为了 InnoDB 写入和页组织。业务唯一交给唯一索引,聚簇组织交给代理主键。