MySQL 主键详解:作用与使用方法

MySQL 主键详解:作用、使用方法与最佳实践(2025–2026 实用版)

主键(Primary Key)是 MySQL 中最核心、最基础的约束之一,理解它能帮助你设计出高效、可维护的表结构。

一、主键到底是什么?核心作用

主键有三个最本质的作用:

  1. 唯一性(Uniqueness)
    表中每一行数据的主键值必须唯一,不能重复,也不能为 NULL
  2. 标识性(Identification)
    主键是唯一能确定一行记录的字段(或字段组合),相当于每条数据的“身份证号”。
  3. 聚集索引(Clustered Index)
    在 InnoDB 引擎(MySQL 默认引擎)中,主键就是聚集索引的依据,表数据按照主键顺序物理存储

一句话总结:
主键 = 唯一不为空 + 决定了数据的物理存储顺序 + 是查找最快的路径

二、主键的几种常见类型对比

类型定义方式示例是否允许 NULL是否自增存储空间适用场景推荐程度(2025–2026)
自然主键(业务字段)order_id VARCHAR(32)中–大业务有天然唯一标识(如订单号、车牌号)★★☆(慎用)
代理主键(自增ID)id BIGINT AUTO_INCREMENT8字节绝大多数业务表★★★★★(强烈推荐)
UUID 主键id CHAR(36) 或 BINARY(16)36/16字节需要全局唯一、分布式系统★★★☆(特定场景)
复合主键(多列)PRIMARY KEY (user_id, role_id)多对多关系表、唯一约束场景★★☆(视情况)

当前主流结论(InnoDB):

  • 95%+ 的业务表都应该使用自增 BIGINT 主键id BIGINT UNSIGNED AUTO_INCREMENT
  • UUID 适合分布式系统,但有性能代价
  • 自然主键在大多数场景下不推荐作为主键(虽然可以作为唯一索引)

三、创建主键的几种写法

-- 方式1:建表时直接定义(最常见)
CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
    username VARCHAR(50) NOT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


-- 方式2:列级约束
CREATE TABLE orders (
    order_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    amount DECIMAL(10,2) NOT NULL
);


-- 方式3:复合主键
CREATE TABLE user_roles (
    user_id BIGINT UNSIGNED NOT NULL,
    role_id INT UNSIGNED NOT NULL,

    PRIMARY KEY (user_id, role_id)
);


-- 方式4:已有表添加主键(慎用)
ALTER TABLE users ADD PRIMARY KEY (id);

四、自增主键最常见的写法(推荐模板)

CREATE TABLE example (
    id          BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',

    -- 业务字段
    user_id     BIGINT UNSIGNED NOT NULL DEFAULT 0,
    title       VARCHAR(200) NOT NULL DEFAULT '',
    status      TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '0=草稿,1=发布,2=删除',
    created_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    -- 索引
    INDEX idx_user_id (user_id),

    PRIMARY KEY (id)
) ENGINE=InnoDB 
  DEFAULT CHARSET=utf8mb4 
  COLLATE=utf8mb4_unicode_ci 
  COMMENT='示例表';

推荐字段顺序
主键 → 业务常用查询字段 → 状态/时间字段 → 其他

五、主键相关的常见问题与注意事项

  1. 为什么不推荐 UUID 做主键?
  • 插入性能差(随机性导致页分裂)
  • 索引占用空间大(36字节 vs 8字节)
  • 排序效率低
  • 联合索引时前缀不友好
  1. 自增 ID 会不会用完?
  • BIGINT UNSIGNED:0 ~ 18446744073709551615(约 1840 亿亿)
  • 即使每天插入 1 亿条,也要用 5000+ 年
  1. 主键能改吗?
    能,但代价极大(会重建整个表和所有二级索引)
    生产环境几乎不要改主键。
  2. 删除主键后还能恢复吗?
    不建议直接删除主键。
    如果误删,建议加回同结构主键(但自增会从 1 开始,除非用 AUTO_INCREMENT = n 指定)。
  3. 外键一定需要主键吗?
    外键引用的一定是被引用表的唯一键(可以是主键,也可以是唯一索引)。

六、实际场景选择建议

场景推荐主键类型理由简述
用户表、订单表、文章表BIGINT 自增顺序插入、高效、简单
分布式系统全局唯一IDUUID v7 / Snowflake / ULID避免 ID 冲突
多对多中间表复合主键(两列)天然唯一 + 节省空间
需要业务含义的编码业务字段 + 唯一索引主键仍用自增,业务码做唯一约束
日志表、监控表BIGINT 自增 或 不设主键追求极致写入性能,可不设主键

七、总结口诀

  • 默认用BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
  • 不建议用:VARCHAR、UUID 做主键(除非有特殊需求)
  • 必须保证:主键唯一、不为空
  • InnoDB 特性:主键 = 聚集索引,决定了数据物理顺序
  • 生产建议:主键字段放在表最前面,命名为 id

你现在是在设计新表,还是在优化老表?
或者有具体的场景(比如分布式系统、日志表、多租户等),我可以给你更针对性的表结构建议。

文章已创建 4547

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部