C# 生成唯一ID方法 C# Guid和雪花算法如何选择和实现

来源:这里教程网 时间:2026-02-21 17:41:33 作者:

Guid 生成的 ID 真的全局唯一吗?

是的,

Guid.NewGuid()
在绝大多数实际场景下可视为全局唯一——它基于时间戳、随机数、MAC 地址(.NET Core/.NET 5+ 已弃用 MAC)等混合生成,碰撞概率极低(理论约 2^122 分之一)。但要注意:它不保证有序、不可预测、且字符串长度固定 36 字符(含连字符),对数据库索引、缓存键、URL 路径都不友好。

常见误用:直接把

Guid.ToString()
存 MySQL 的
VARCHAR(36)
当主键——会导致索引碎片严重、写入性能下降。更合理的做法是:
Guid.ToByteArray()
BINARY(16)
,或用
Guid.ToString("N")
去掉连字符(32 字符),再加索引。

雪花算法(Snowflake)在 C# 怎么安全实现?

雪花算法生成的是 64 位

long
类型递增 ID(如
1892347654321098765
),带时间戳、机器 ID、序列号,天然有序、紧凑、可排序。C# 没有官方实现,但可用成熟开源库,比如
IdGen
或手写轻量版。

关键实操点:

IdGen
需显式配置
IdGeneratorOptions
,其中
MachineId
必须在集群中唯一(可通过配置中心/环境变量注入,不能硬编码)
若用自研,注意系统时钟回拨:必须阻塞或抛异常(不能容忍重复 ID),推荐用
SystemClock
封装 +
Interlocked
控制序列号
默认时间纪元是
2022-01-01
(IdGen),不是 Twitter 原版的
2010-11-04
,跨系统对接前要对齐
生成的
long
可直接映射到 SQL Server 的
BIGINT
或 PostgreSQL 的
BIGSERIAL
,无需字符串转换

Guid 和 Snowflake 到底怎么选?

选哪个不取决于“哪个更高级”,而取决于你的数据写入模式和下游依赖:

单机小项目、快速原型、或 ID 只用于内部标识(如日志 correlationId)→ 用
Guid.NewGuid()
,简单无脑,零配置
高并发写入(如订单、消息)、需要按时间范围查询、要分库分表路由、或前端要展示“短 ID” → 选 Snowflake(或其变种如
ULID
/
KSUID
用了 Entity Framework Core?
Guid
默认支持
ValueGeneratedOnAdd()
;Snowflake 需手动赋值或重写
SaveChangesAsync
插入前生成
部署在容器/K8s?
Guid
无状态;Snowflake 的
MachineId
必须从 Pod 名、IP 或配置中心稳定获取,否则重启后可能重复

别忽略 ID 的“下游成本”

很多人只盯着生成逻辑,却忘了 ID 一旦落库、进缓存、发 Kafka、被前端拼接进 URL,就锁死了格式和语义。比如:

— 把

Guid
存成
VARCHAR
后想改成
BINARY
,要全量迁移;

— Snowflake 的 64 位

long
在 JavaScript 中会精度丢失(
Number.MAX_SAFE_INTEGER
是 2^53),前端必须传字符串;

— 有些老系统 API 约定 ID 是 32 位整数,硬上 Snowflake 会直接报错。

真正难的不是生成 ID,而是让整个数据链路能一致地理解、传输、存储它。设计 ID 方案时,先翻一遍上下游接口文档和数据库 schema。

相关推荐