目 录CONTENT

文章目录

使用雪花ID和UUID作为MySQL主键的影响分析

在等晚風吹
2025-03-19 / 0 评论 / 0 点赞 / 5 阅读 / 0 字 / 正在检测是否收录...

使用雪花ID和UUID作为MySQL主键的影响分析

前言

在设计MySQL数据库表时,MySQL官方建议使用连续自增的主键ID(auto_increment),而不是UUID或者雪花ID(Snowflake ID)。那么,为什么不推荐使用UUID?UUID究竟有哪些缺点?

本篇文章将分析这个问题,探讨内部原因,并通过实验数据来直观展示不同主键策略对数据库性能的影响。

目录

  1. MySQL程序实例
  2. UUID与自增ID的索引结构对比
  3. 总结

MySQL程序实例

1.1 创建测试表

为了验证不同主键策略的影响,我们建立三张表:

  • user_auto_key:主键采用auto_increment的自增ID。
  • user_uuid:主键采用UUID。
  • user_random_key:主键采用雪花ID(随机不连续的18位Long类型)。

表结构示例如下:

CREATE TABLE user_auto_key (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_name VARCHAR(50),
    sex CHAR(1),
    address VARCHAR(255),
    city VARCHAR(100),
    email VARCHAR(100),
    state VARCHAR(10)
);

CREATE TABLE user_uuid (
    id CHAR(36) PRIMARY KEY,
    user_name VARCHAR(50),
    sex CHAR(1),
    address VARCHAR(255),
    city VARCHAR(100),
    email VARCHAR(100),
    state VARCHAR(10)
);

CREATE TABLE user_random_key (
    id BIGINT PRIMARY KEY,
    user_name VARCHAR(50),
    sex CHAR(1),
    address VARCHAR(255),
    city VARCHAR(100),
    email VARCHAR(100),
    state VARCHAR(10)
);

1.2 测试程序

为了测试插入数据的效率,我们使用Spring Boot + JDBC Template + JUnit + Hutool来完成数据插入操作。每张表插入相同数量的随机数据。

@Test
void testDBTime() {
    StopWatch stopwatch = new StopWatch("SQL执行时间统计");
    
    // 自增ID
    final String insertSql = "INSERT INTO user_auto_key(user_name, sex, address, city, email, state) VALUES(?,?,?,?,?,?)";
    List<UserKeyAuto> insertData = autoKeyTableService.getInsertData();
    stopwatch.start("自增ID表插入");
    jdbcTemplateService.insert(insertSql, insertData, false);
    stopwatch.stop();

    // UUID
    final String insertSql2 = "INSERT INTO user_uuid(id, user_name, sex, address, city, email, state) VALUES(?,?,?,?,?,?,?)";
    List<UserKeyUUID> insertData2 = uuidKeyTableService.getInsertData();
    stopwatch.start("UUID表插入");
    jdbcTemplateService.insert(insertSql2, insertData2, true);
    stopwatch.stop();

    // 雪花ID
    final String insertSql3 = "INSERT INTO user_random_key(id, user_name, sex, address, city, email, state) VALUES(?,?,?,?,?,?,?)";
    List<UserKeyRandom> insertData3 = randomKeyTableService.getInsertData();
    stopwatch.start("雪花ID表插入");
    jdbcTemplateService.insert(insertSql3, insertData3, true);
    stopwatch.stop();

    System.out.println(stopwatch.prettyPrint());
}

1.3 插入数据的结果

在测试插入100万条数据后,我们发现:

  • user_auto_key表的插入速度最快。
  • user_random_key表次之。
  • user_uuid表最慢。

1.4 效率测试

插入数据量 100 万后,再追加 10 万数据,结果如下:

主键策略100万数据插入时间追加10万数据时间
自增ID10.2 秒1.1 秒
雪花ID12.4 秒1.5 秒
UUID20.8 秒3.6 秒

可以看到,UUID的插入性能在数据量增加后急剧下降。

UUID与自增ID的索引结构对比

2.1 自增ID的索引结构

自增ID是顺序递增的,InnoDB存储时会按顺序写入,避免了页分裂,提升了存储效率。

2.2 UUID的索引结构

UUID是随机的,导致数据分布不均匀,会出现以下问题:

  • 频繁的页分裂,导致存储碎片。
  • 需要大量的随机I/O,降低插入效率。
  • 需要额外的磁盘空间。

2.3 自增ID的缺点

虽然自增ID有较好的插入性能,但也存在一些缺点:

  1. 信息泄露:如果数据库被爬取,可以推测业务增长情况。
  2. 并发争抢:高并发插入时,主键的上界可能成为争抢热点。
  3. 锁争用Auto_increment 锁机制可能影响性能。

总结

本篇文章通过实验分析了自增ID、UUID和雪花ID在MySQL中的插入效率,发现:

  • 自增ID的插入效率最高,适用于大多数业务场景。
  • UUID插入性能最差,容易导致索引碎片,不推荐使用。
  • 雪花ID介于两者之间,适用于分布式系统。

在实际开发中,建议优先使用自增ID,但如果业务对分布式唯一性有强需求,可考虑雪花ID作为主键。

0

评论区