概述
主键ID的几种生成方式,一般有以下几种:
- 自增
- UUID
- 雪花算法
下面针对这3种主键ID生成方式,简单的介绍一下优缺点。
自增
1、优点:
- 简单、易用,无需额外的配置,数据库会自动生成主键ID。
- 自增id是有序的,所以查询数据时效率高。
2、缺点:
- 如果表中存在大量数据,会导致主键ID的空间不够用。
- 数据库迁移或多库多表的情况下,主键ID的生成可能会出现重复。
3、优化方案:
- 针对多主库(主从库也需同样设置),可以设置不同的初始值,步长可以根据库的数量设置。比如两个主库,主库1初始值1,主库2初始化值2,步长2,这样主库1的主键ID为1,3,5,主库2的主键ID为2,4,6,以此类推。
- 增加ID的空间长度,可以使用无符号整型。int类型最大值是2147483647,uint类型最大值是4294967295
- 在数据迁移或合并时,可以将自增ID与标识列做联合主键。比如:在多租户系统中,可以设置租户ID作为标识列,租户ID与自增ID联合作为主键。
UUID
1、优点:
- UUID保证了唯一性,不会出现重复的主键ID。
- 本地生成,代码非常简单
- 数据迁移、合并、主从库同步等操作时,不会出现主键ID的冲突。
2、缺点:
- UUID是无序的,查询效率低。
- UUID占用空间大,长度至少36个字符,就算去掉分隔符也有32个字符。
3、优化方案:
- 转换成16位字符串,减少占用空间
private static string GenerateShortGuid()
{
long i = 1;
foreach (byte b in Guid.NewGuid().ToByteArray())
{
i *= ((int)b + 1);
}
return string.Format("{0:x}", i - DateTime.Now.Ticks);
}
- 转换成19位的长整型,提高查询效率
private static long GenerateLongID()
{
byte[] buffer = Guid.NewGuid().ToByteArray();
return BitConverter.ToInt64(buffer, 0);
}
雪花算法
1、雪花算法原理:
- 时间戳(41位):占据ID的最高位,用于记录ID生成的时间。由于时间戳是毫秒级的,因此可以保证在单个节点上生成的ID是递增的。同时,时间戳也起到了区分不同节点生成ID的作用。
- 工作机器ID(10位):包括5位的数据中心ID和5位的机器ID。这部分用于标识生成ID的节点,确保不同节点生成的ID不会冲突。
- 序列号(12位):用于记录同一毫秒内生成的ID序号。由于序列号部分有12位,因此可以在同一毫秒内生成4096个不同的ID。
2、优点:
- 长整型ID,支持大数据量
- 根据时间戳有序生成,保证写入性能(因为插入数据时需要创建索引)
- 生成ID的速度快,满足高并发场景的需求
3、缺点:
- 依赖机器时钟,如果机器上时钟回拨,可能导致ID重复
- 单机上生成的ID是递增的,在分布式环境下,可能不是全局递增的
其它主键生成方式
- 利用redis原子操作INCR生成主键ID。
- 利用数据库维护流水号,根据一定的规则生成主键ID。比如:[业务编号]+[yyyyMMdd]+[流水号]