主键设计的正确姿势

487 阅读5分钟

设计主键的好处

数据库设计中通常都建议为表设计一个主键。它有几个好处:

  1. 唯一性:主键保证了表中每一行数据的唯一性,避免了数据重复和冗余。

  2. 数据完整性:主键可以确保数据的完整性,防止数据行缺失或重复。

  3. 数据检索效率:主键通常会被数据库系统用作索引,提高数据检索的效率。

  4. 数据关联:主键可以用来建立表与表之间的关联关系,实现数据的关联查询和连接操作。

主键设计方案

主键的设计常见的有以下几种种方案:

  1. 自增ID
  2. uuid
  3. 分布式自增ID
  4. 组合主键
  5. 业务字段作为主键,及其变种
  6. 时间戳

上面的各种方法总结起来本质其实就是两大类,一类是利用算法或工具生成合适的ID,一类是基于业务特性选择或者组合合适的ID

这里主要介绍生成方式的ID,选择式的按经验场景选择就好

自增ID

自增ID一般就是借助MySQL auto_increament(其它数据库如oracle、pg则使用sequence),像下面这样:

create table ‘test’ (   ‘id’  int(16) NOT NULL AUTO_INCREMENT,   ‘name’  char(10) DEFAULT NULL,   PRIMARY KEY(‘id’) ) ENGINE = InnoDB;

优点是使用便利,性能好,占用空间小,除了可以保证唯一性外,还可以单调递增,连续递增(在某些情况下会产生空洞,比如事务冲突时,造成回滚,那主键ID就会跳跃。)。

但是自增ID也不总是有优势的,比如:

  • 可预测,即可以遍历所有ID,造成风险

  • 不适用于分布式架构,多个数据库实例可能产生重复ID

  • 高并发性问,在高并发环境下,自增ID可能会导致竞争和锁定问题,影响系统的性能和伸缩性

UUID

那怎么解决自增ID的问题,其实有一种方案就是UUID,使用通用算法生成唯一ID。它是一种分布式ID生成算法,是一种用于标识信息的唯一标识符。它是一个128位的数字,通常以32个十六进制数字的形式表示,如 "550e8400-e29b-41d4-a716-446655440000"。UUID 的唯一性是基于时间戳、计算机的 MAC 地址、随机数等因素生成的,因此几乎可以保证在全球范围内的唯一性。

主要特点包括:

  1. 全局唯一性:UUID 是全局唯一的,几乎可以保证在全球范围内不会重复。
  2. 分布式生成:UUID 可以在分布式系统中生成,而不需要中心化的管理。
  3. 随机性:UUID 的生成是基于时间戳和随机数的组合,因此具有一定的随机性。
  4. 不可预测性:由于 UUID 是基于随机数生成的,因此具有一定的不可预测性,不容易被猜测。
  5. 长度固定:UUID 的长度固定为128位,不受标识符长度限制。

它在保持同样唯一性的前提下,比较好的解决了自增ID中分布式、可预测的问题。

但它同样带来了新的问题:

  1. 可读性差:相比较自增ID等数字型标识符,UUID通常是一串32位的十六进制字符,不易于人类阅读和理解。
  2. 较大的存储空间:UUID通常是128位长,相比较自增ID等较短的标识符,会占用更多的存储空间。这可能会导致在大规模数据存储时占用更多的存储空间。
  3. 性能影响:由于UUID是随机生成的,而不是连续递增的,因此可能会导致数据插入时的性能问题。在某些数据库系统中,使用UUID作为主键可能会导致性能下降。
  4. 查询效率:在某些数据库系统中,使用UUID作为主键可能会影响索引的效率。由于UUID是随机生成的,可能导致索引树的分裂,影响查询性能。

对于1、2两点比较好理解。3、4主要从相对于自增ID来说性能方面考虑,产生这种情况的原因主要是因为数据库使用B+树作为索引,而uuid是随机无序的,所以插入B+树的时候很可能产生页分裂。另外使用 UUID 作为主键时,新记录的插入位置是随机的,不会按插入时间顺序存储的,这会导致数据在磁盘上的分散存储,如果按范围查找会增加了磁盘寻址的开销

分布式自增ID

雪花算法(Snowflake)

它是一种用于生成分布式唯一ID的算法,最初由Twitter开发并开源。Snowflake算法的核心思想是将一个64位的ID分成不同的部分,每部分代表不同的信息,以确保生成的ID在分布式系统中是唯一的。

Snowflake算法生成的64位ID通常由以下部分组成:

  1. 时间戳部分(41位):记录生成ID的时间戳,精确到毫秒级别,可以支持69年的时间范围。
  2. 机器ID部分(10位):记录机器的唯一标识符,通常是数据中心ID和机器ID的组合,可以支持1024个不同的机器。
  3. 序列号部分(12位):在同一毫秒内生成的ID的序列号,可以支持每台机器每毫秒生成4096个不同的ID。

D0A20BB0-5CE1-47BB-B8E3-57EDF20E0DFE.png

优点:

  1. 高性能:Snowflake算法生成的ID是递增的,不需要访问数据库或进行网络通信,生成速度快。
  2. 唯一性:Snowflake算法生成的ID在分布式系统中是唯一的,不会出现重复的情况。
  3. 分布式:Snowflake算法适用于分布式系统,可以在多台机器上生成唯一ID。