以下是关于为什么不推荐使用 UUID 作为主键的详细说明和例子:


1. 性能问题

原因:

UUID 通常为 128 位的数据,如果以字符串形式存储(如 char(36)varchar(36)),会占用大量存储空间。相较之下,自增的整数主键通常是 4 字节(INT)或 8 字节(BIGINT),空间更小且效率更高。此外,UUID 的随机性会影响数据库的缓存命中率,从而降低查询和写入性能。

举例:

  • UUID: 插入数据时,生成的 UUID 是随机的,如 550e8400-e29b-41d4-a716-446655440000,它可能被插入到索引的任意位置,这会导致索引频繁重组。
  • 自增整数: 使用自增 ID,主键的值是连续增长的,例如 1, 2, 3,...,新数据会按顺序插入索引的末尾,索引维护更高效,写入性能更优。

2. 可读性差

原因:

UUID 是随机的长字符串,不容易通过人工快速识别或记忆。相比之下,数字主键通常简单易懂,有助于调试和问题排查。

举例:

  • UUID: 日志中记录一条错误信息时,主键为 f47ac10b-58cc-4372-a567-0e02b2c3d479。开发者在排查问题时,必须复制完整的 UUID,而无法快速记忆或手动输入。
  • 自增整数: 如果主键是 1024,开发者可以轻松记住并输入到查询语句中,例如 SELECT * FROM orders WHERE id = 1024;

3. 索引碎片化

原因:

UUID 的随机性会导致数据插入索引时,索引树(如 B+ 树)出现较多的非顺序写入。这会增加索引碎片化的可能性,降低索引查询性能。

举例:

  • UUID: 数据库中现有记录主键为 0001xxxx, 0002xxxx, 0003xxxx。插入新记录 a1b2xxxx,由于新主键值的随机性,它会被插入到索引树的中间部分,导致索引重新平衡。
  • 自增整数: 主键为 1000, 1001, 1002,... 的表中插入新记录 1003,只需要在索引末尾追加,索引无需重组。

4. 复杂性

原因:

UUID 的生成需要依赖算法(如版本 1 或版本 4 的 UUID 生成器),并可能要求系统时间或随机数生成器的支持。对于跨系统或分布式场景,还需要额外的配置以避免冲突,而自增主键则更简单。

举例:

  • UUID: 在分布式系统中,不同节点可能生成重复的 UUID,必须依赖高质量的 UUID 生成工具来避免冲突。此外,某些 UUID 生成方式(如基于时间的版本 1)可能会暴露系统信息(如时间戳或网卡地址),带来安全隐患。
  • 自增整数: 即使在分布式场景中,可以为每个节点分配不同的 ID 段(如节点 1 使用 1-1000,节点 2 使用 1001-2000),简单易行。

总结:

虽然 UUID 的全局唯一性在某些场景(如分布式系统或数据同步)下很有用,但因其性能和复杂性问题,建议谨慎选择。若一定要用 UUID,可以考虑优化策略,例如:

  • 使用更紧凑的存储方式(如 binary(16))。
  • 配合其他索引或策略(如分区表)来降低性能影响。