UUID vs 自增 ID:数据库主键选择指南

全面对比 UUID 和自增 ID 作为数据库主键的优缺点,帮助你做出正确的技术选型。

UUID 专题 2026-06-03 8 分钟

UUID vs 自增 ID:数据库主键选择指南

选择数据库主键是数据库设计的核心决策。本文对比 UUID 和自增 ID 的优缺点。

对比总览

特性自增 IDUUID
唯一性单库唯一全局唯一
有序性✅ 有序❌ 无序(V4)
存储大小4-8 字节16 字节
可预测性可预测不可预测
分布式支持❌ 需要协调✅ 无需协调
安全性低(可遍历)高(不可遍历)
性能高中

自增 ID

优势

  1. 性能好:B+ 树插入有序,页分裂少
  2. 存储小:4 字节(INT)或 8 字节(BIGINT)
  3. 可读性好:1, 2, 3 简单直观
  4. 调试方便:容易追踪数据

劣势

  1. 分布式困难:多库需要协调,避免 ID 冲突
  2. 安全性低:可遍历,容易被猜测
  3. 数据迁移麻烦:不同库的 ID 可能冲突
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100)
);

UUID

优势

  1. 全局唯一:无需协调,各节点独立生成
  2. 安全性高:不可遍历,难以猜测
  3. 数据迁移方便:不同库的数据可以合并
  4. 离线生成:不依赖数据库

劣势

  1. 性能差:无序插入导致页分裂
  2. 存储大:16 字节,比 BIGINT 大一倍
  3. 可读性差:难以记忆和调试
  4. 索引碎片化:随机插入导致索引碎片
CREATE TABLE users (
    id CHAR(36) PRIMARY KEY,
    name VARCHAR(100)
);

性能测试

插入性能(100 万条数据)

方案耗时索引大小
自增 ID12s30MB
UUID V425s65MB
有序 UUID14s35MB

查询性能(按 ID 查询)

方案平均耗时
自增 ID0.1ms
UUID V40.3ms
有序 UUID0.15ms

选型建议

选择自增 ID 的场景

  • 单库单表
  • 内部系统(不需要隐藏 ID)
  • 性能要求极高
  • 数据量不大(< 1 亿)

选择 UUID 的场景

  • 分布式系统
  • 需要数据合并
  • 安全性要求高(不暴露 ID)
  • 需要离线生成 ID

混合方案

-- 内部使用自增 ID,外部暴露 UUID
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE NOT NULL,
    name VARCHAR(100)
);

-- 查询时使用 UUID
SELECT * FROM users WHERE uuid = 'xxx';

-- 内部关联使用自增 ID
SELECT * FROM orders WHERE user_id = 123;

优化方案

1. 有序 UUID

// 使用时间戳前缀
public static UUID orderedUUID() {
    long time = System.currentTimeMillis();
    UUID uuid = UUID.randomUUID();
    return new UUID(
        (time << 22) | (uuid.getMostSignificantBits() & 0x3FFFFF),
        uuid.getLeastSignificantBits()
    );
}

2. Snowflake 算法

// 64 位有序 ID
long id = snowflake.nextId();
// 1635123456789012345

3. ULID

01ARZ3NDEKTSV4RRFFQ69G5FAV

总结

没有绝对的好坏,关键是根据场景选择:

  • 单库、性能优先 → 自增 ID
  • 分布式、安全优先 → UUID
  • 需要有序 + 分布式 → Snowflake 或有序 UUID

📚 相关文章