⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7478495083374559270 「码农liuxin」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

在 MySQL 中,使用 UUID 作为主键 在大表中可能会导致性能问题,尤其是在插入和修改数据时效率较低。以下是详细的原因分析,以及为什么修改数据会导致索引刷新,以及字符主键为什么效率较低。

1. UUID 作为主键的问题

(1)UUID 的特性

  • UUID 是一个 128 位的字符串,通常表示为 36 个字符(例如:550e8400-e29b-41d4-a716-446655440000)。
  • UUID 是全局唯一的,适合分布式系统中生成唯一标识。

(2)UUID 作为主键的缺点

1. 索引效率低

  • 索引大小:UUID 是字符串类型,占用空间较大(36 字节),而整型主键(如 BIGINT)仅占用 8 字节。索引越大,存储和查询的效率越低。
  • 索引分裂:UUID 是无序的,插入新数据时,可能会导致索引树频繁分裂和重新平衡,影响性能。

2. 插入性能差

  • 随机性:UUID 是无序的,每次插入新数据时,新记录可能会插入到索引树的任意位置,导致索引树频繁调整。
  • 页分裂:InnoDB 存储引擎使用 B+ 树作为索引结构,随机插入会导致页分裂,增加磁盘 I/O 操作。

3. 查询性能差

  • 比较效率低:字符串比较比整型比较慢,尤其是在大表中,查询性能会显著下降。
  • 索引扫描范围大:UUID 索引占用的空间大,导致索引扫描的范围更大,查询效率降低。

2. 修改数据导致索引刷新的原因

(1)索引的作用

  • 索引是为了加速查询而创建的数据结构(如 B+ 树)。
  • 当数据被修改时,索引也需要同步更新,以保持数据的一致性。

(2)修改数据对索引的影响

  • 更新主键:

    • 如果修改了主键值,MySQL 需要删除旧的主键索引记录,并插入新的主键索引记录。
    • 这个过程会导致索引树的调整,增加磁盘 I/O 操作。
  • 更新非主键列:

    • 如果修改的列是索引列(如唯一索引、普通索引),MySQL 需要更新对应的索引记录。
    • 这个过程也会导致索引树的调整。

(3)UUID 主键的额外开销

  • 由于 UUID 是无序的,修改主键值时,新值可能会插入到索引树的不同位置,导致索引树频繁调整。
  • 相比于有序的主键(如自增 ID),UUID 主键的修改操作代价更高。

3. 字符主键导致效率降低的原因

(1)存储空间大

  • 字符主键(如 UUID)占用的存储空间比整型主键大。
  • 索引的大小直接影响查询性能,索引越大,查询时需要的磁盘 I/O 操作越多。

(2)比较效率低

  • 字符串比较比整型比较慢,尤其是在大表中,查询性能会显著下降。
  • 例如,WHERE id = '550e8400-e29b-41d4-a716-446655440000' 的效率低于 WHERE id = 12345。

(3)索引分裂

  • 字符主键通常是无序的,插入新数据时,可能会导致索引树频繁分裂和重新平衡,影响性能。

4. 如何优化 UUID 主键的性能

(1)使用有序 UUID

  • 使用有序 UUID(如 UUIDv7),减少索引分裂和页分裂。
  • 有序 UUID 的生成方式可以基于时间戳,保证插入顺序。

(2)将 UUID 存储为二进制

  • 将 UUID 存储为 BINARY(16) 而不是 CHAR(36),减少存储空间。

    sql 代码解读复制代码CREATE TABLE users (
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(255)
    );

(3)使用自增主键 + UUID

  • 使用自增主键作为物理主键,UUID 作为逻辑主键。

    sql 代码解读复制代码CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) UNIQUE,
    name VARCHAR(255)
    );

(4)分区表

  • 对大表进行分区,减少单个索引树的大小,提高查询性能。

~Summary

  • UUID 作为主键的缺点:

    • 索引效率低,插入和查询性能差。
    • 修改数据时,索引需要频繁刷新,导致性能下降。
  • 字符主键效率低的原因:

    • 存储空间大,比较效率低,索引分裂频繁。
  • 优化建议:

    • 使用有序 UUID 或二进制存储。
    • 结合自增主键和 UUID。
    • 对大表进行分区。
文章目录
  1. 1. 1. UUID 作为主键的问题
    1. 1.0.1. (1)UUID 的特性
    2. 1.0.2. (2)UUID 作为主键的缺点
      1. 1.0.2.1. 1. 索引效率低
      2. 1.0.2.2. 2. 插入性能差
      3. 1.0.2.3. 3. 查询性能差
  • 2. 2. 修改数据导致索引刷新的原因
    1. 2.0.1. (1)索引的作用
    2. 2.0.2. (2)修改数据对索引的影响
    3. 2.0.3. (3)UUID 主键的额外开销
  • 3. 3. 字符主键导致效率降低的原因
    1. 3.0.1. (1)存储空间大
    2. 3.0.2. (2)比较效率低
    3. 3.0.3. (3)索引分裂
  • 4. 4. 如何优化 UUID 主键的性能
    1. 4.0.1. (1)使用有序 UUID
    2. 4.0.2. (2)将 UUID 存储为二进制
    3. 4.0.3. (3)使用自增主键 + UUID
    4. 4.0.4. (4)分区表
  • 5. ~Summary