为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?

为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?


推荐自增主键的五大原因

先记住一个前提:InnoDB 是聚簇索引,整张表的数据就是按主键顺序存在 B+ 树叶子页里的。这是所有区别的根源。

1. 顺序追加写入,大幅减少页分裂

sql 复制代码
CREATE TABLE user_auto (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

自增 ID 持续递增,新数据永远追加在数据页末尾。页面填满后新开一页就行,几乎不会触发页分裂。

通俗比喻:就像往文件夹里按 1、2、3 的顺序放文件,永远往后塞;UUID 是随机往里插,文件夹撑破了就要拆分、挪数据,大量消耗磁盘 IO,产生索引碎片。

2. 页面填充率高,磁盘空间利用率好

顺序写入页面填充率接近 15/16;UUID 随机插入频繁页分裂,页面经常只填充一半,大量磁盘空间闲置浪费。

3. 主键连续,范围查询和排序性能极强

日常高频 SQL:id > 100 AND id < 200,或者 ORDER BY id DESC LIMIT 10。自增主键在磁盘上物理连续,走顺序 IO,直接扫过去。

UUID 没规律,ORDER BY uuid 变成随机 IO,磁盘头来回跳,性能差距明显。

4. 主键字段更小,二级索引整体瘦身,B+ 树更矮

BIGINT 只占 8 字节;字符串 UUID 占 36 字节,二进制 UUID 也要 16 字节。

InnoDB 所有二级索引的叶子节点都存主键值。主键越大,索引越胖。一张表 5 个二级索引,千万级数据可能多出几百 MB。

更重要的是:主键越小,B+ 树每层能放下的索引条目越多,树的高度就越低 。同样是千万级数据,8 字节主键可能树高 3 层,36 字节 UUID 可能树高 4 层。多一层就多一次磁盘 IO。

5. 自增锁机制完善,高并发写入稳定

MySQL 默认 innodb_autoinc_lock_mode = 1,单行插入几乎无锁,批量插入也做了轻量优化,并发写入吞吐稳定。


UUID 做主键的优缺点

屏幕中栏贴两套建表 SQL,上半部分讲优点,下半部分标红讲缺点。

两种 UUID 建表写法

sql 复制代码
-- 普通字符串 UUID,可读性强,但最占空间
CREATE TABLE user_uuid_str (
    id CHAR(36) PRIMARY KEY,
    name VARCHAR(50)
) ENGINE=InnoDB;

-- MySQL 推荐二进制存储,省一半空间
CREATE TABLE user_uuid_bin (
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(50)
) ENGINE=InnoDB;

UUID 三大优点

  1. 天然全局唯一:分库分表、多服务分布式架构下,各节点生成 ID 不会重复,不用依赖数据库发号。
  2. 防爬虫泄露业务体量 :自增 ID 容易被遍历,/order/1、/order/2 一眼看出订单量;UUID 无规律,安全性更高。
  3. 去中心化生成:应用层直接生成,不访问数据库,减轻 DB 压力。

UUID 五大硬伤(重点标红)

  1. 写入随机,页分裂和索引碎片严重

    常规 UUID 随机分布,插入位置不可控,数据量大后碎片率极高,频繁 OPTIMIZE TABLE 都很难修复。

    补充知识点 :UUID v1 带时间戳,是有序的,可以缓解页分裂。但它自带物理 MAC 地址,有隐私泄露风险,业务上极少使用。

  2. 字段体积大,索引膨胀严重

    字符串 UUID 是 BIGINT 的 4 倍多,二级索引跟着一起胖,磁盘和内存占用双双上涨。

  3. 无法利用磁盘顺序 IO 和 CPU 缓存

    主键无序,缓存命中率低。精准主键查询还行,范围查询和排序性能拉胯。

  4. 主键没有顺序业务价值

    ORDER BY id 对 UUID 来说完全是随机排序,不像自增 ID 能反映创建时间,没法靠 ID 做时间分页。

  5. 高并发写入拖累 TPS

    随机写频繁刷新缓冲池,热点数据页来回换入换出,数据库吞吐明显下降。


选型决策树

使用场景 首选主键方案 选型逻辑
单机单库、不分片 BIGINT 自增 性能、空间、维护全最优
分布式、分库分表 雪花算法(Snowflake) 趋势递增 + 全局唯一,兼顾自增和 UUID 的优点
必须去中心化、不能依赖发号器 BINARY(16) UUID 二进制压缩,减少空间损耗
防爬、隐藏业务数据 UUID / 雪花 无规律 ID,防止批量遍历

如果必须用 UUID,至少做这个优化

sql 复制代码
-- 插入:字符串 UUID 转二进制,36 字节变 16 字节
INSERT INTO user_uuid_bin VALUES (UUID_TO_BIN(UUID()), 'Alice');

-- 查询:二进制转回可读字符串
SELECT BIN_TO_UUID(id), name FROM user_uuid_bin;

二者没有绝对优劣,核心看部署架构。单机优先自增,分布式优先雪花算法;UUID 只在强去中心化、隐私防爬时兜底使用,一定要用二进制压缩存储。


额外拓展

第一,线上禁止直接用 CHAR(36) UUID 做主键,实在要用必须 BINARY(16);

第二,分布式不要直接上 UUID,优先雪花算法、百度 UidGenerator 这类有序全局 ID ;

第三,所有隔离级别下,自增主键写入性能都稳定,UUID 则全级别都有 IO 损耗。

相关推荐
卓怡学长11 小时前
w195基于ssm“Fitfrend”个性化健身
java·intellij-idea
沫璃染墨11 小时前
《从零入门Linux系统篇(五十三):线程篇·六——线程互斥详解:从并发问题到mutex互斥锁》
linux·运维·服务器·开发语言·后端·架构·系统架构
程序员-Benothing11 小时前
Shell循环教程:for、while、until、break、continue详解
linux·运维·服务器
lusklusklusk11 小时前
Oracle数据库基础之10_性能优化
数据库·oracle·性能优化
旺仔Sec11 小时前
2026年江西省职业院校技能大赛(高职组)麒麟工坊运维保障竞赛样题
运维
Omics Pro11 小时前
预测性虚拟细胞中显式机理算子
大数据·数据库·人工智能·python·算法·机器学习·自然语言处理
看浪的路人11 小时前
第5讲:Prompt 管理与版本追踪
大数据·数据库·elasticsearch
驭渊的小故事11 小时前
算法实战:滑动窗口、素数枚举与字符串模拟(三道经典题解)
java·算法
雪落漂泊11 小时前
Linux基本指令(下)
java·linux·服务器
小白的码BUG之路11 小时前
Ubuntu -- 使用命令firewall-cmd
linux·运维·服务器