本文以 Go 为例对比当前热门的 id 生成器。由于特性与 Snowflake 相同,美团 Leaf、百度 UidGenerator、滴滴 TinyId 未列出。
对比项目
- 二进制位长:ID原始二进制长度(位),影响全局唯一性的概率空间。
 - 文本长度:编码后字符串长度,影响存储与传输效率。
 - 有序性(K-Sortable):是否按生成时间排序,对数据库索引友好性至关重要。
 - 安全性:是否使用加密安全的随机源(如Crypto API),避免预测风险。
 - 时间嵌入:是否包含时间戳,支持按时间范围查询。
 - 分布式友好:是否依赖中心节点或机器ID分配,影响水平扩展复杂度。
 - 主要优点:核心优势场景。
 - 主要缺点:关键限制或风险。
 
对比表格
| 方案 | 二进制位长 | 文本长度 | 有序性 | 安全性 | 时间嵌入 | 分布式友好 | 主要优点 | 主要缺点 | 
|---|---|---|---|---|---|---|---|---|
| Snowflake | 64 | 19数字 | 严格递增 | 高 | 是 | ❌(需机器ID) | 高性能、严格有序、空间效率高 | 依赖时钟同步,机器ID管理复杂 | 
| Sonyflake | 64 | 19数字 | 严格递增 | 高 | 是 | ❌(需机器ID) | 改进时钟回拨处理 | 生态支持较少 | 
| UUIDv4 | 128 | 36字符 | 无序 | 高 | 否 | ✅ | 全局唯一、无协调 | 存储开销大,索引效率低 | 
| UUIDv7 | 128 | 36字符 | 趋势递增 | 高 | 是 | ✅ | 时间有序、IETF标准 | 文本较长 | 
| ShortUUID | 128 | 22字符 | 无序 | 高 | 否 | ✅ | 压缩UUID,减少存储 | 仍无序,兼容性风险 | 
| NanoID | 126 | 21字符 | 无序 | 高 | 否 | ✅ | 极短、生成快(比UUID快60%) | 无序,不适合时序场景 | 
| ULID | 128 | 26字符 | 趋势递增 | 高 | 是 | ✅ | 可排序、Base32无混淆字符 | 毫秒精度,高并发可能碰撞 | 
| KSUID | 160 | 27字符 | 趋势递增 | 高 | 是 | ✅ | 时间精度高(秒级)、Base62紧凑 | 位长较大 | 
| XID | 96 | 24字符 | 趋势递增 | 中 | 是 | ✅ | MongoDB原生支持,生成快 | 随机性弱于UUID | 
| Sqids | 可变 | <10字符 | 无序 | 低 | 否 | ✅ | 极短、人类可读 | 非全局唯一,需上下文 | 
注:
- 有序性:
 
- 严格递增:同毫秒内通过序列号保序(如Snowflake)。
 - 趋势递增:仅时间戳部分有序,同毫秒内随机(如UUIDv7)。
 - 安全性:高 = 使用
 Crypto API;中 = 混合随机源;低 =Math.random()。- 分布式友好:✅ = 无需中心协调;❌ = 需机器ID或时钟同步。
 - 文本长度:基于默认编码(如UUIDv4为Hex,NanoID为Base64)。
 
总结
- 需要严格时序与高性能:选 Snowflake/Sonyflake。
 - 全局唯一且无需协调:UUIDv7 或 ULID/KSUID。
 - 紧凑性与速度优先:NanoID 或 ShortUUID。
 - 人类可读短ID:Sqids。
 - 关键趋势:UUIDv7 和 ULID 因平衡时序性、分布式友好及标准化,成为现代系统的新推荐,而 NanoID 在轻量级场景持续流行。
 
测试代码
package main
import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
	"github.com/bwmarrin/snowflake"
	"github.com/gofrs/uuid"
	"github.com/jaevor/go-nanoid"
	"github.com/lithammer/shortuuid/v4"
	"github.com/oklog/ulid"
	"github.com/rs/xid"
	"github.com/segmentio/ksuid"
	"github.com/sony/sonyflake"
    "github.com/sqids/sqids-go"
)
func main() {
	snowflakeTest()
	sonyflakeTest()
	uuidTest()
	shortuuidTest()
	nanoidTest()
	ulidTest()
	xidTest()
	ksuidTest()
}
func snowflakeTest() {
	n, _ := snowflake.NewNode(1)
	id := n.Generate().String()
	fmt.Println("snowflake:", id, "length:", len(id))
}
func sonyflakeTest() {
	t := time.Now()
	s := sonyflake.NewSonyflake(sonyflake.Settings{
		StartTime: t,
		MachineID: func() (uint16, error) {
			return 1, nil
		},
		CheckMachineID: func(u uint16) bool {
			return true
		},
	})
	id, _ := s.NextID()
	fmt.Println("sonyflake:", id, "length:", len(strconv.FormatUint(id, 10)))
}
func uuidTest() {
	id, _ := uuid.NewV4()
	fmt.Println("uuid:", id.String(), "length:", len(id.String()))
}
func shortuuidTest() {
	id := shortuuid.New()
	fmt.Println("shortUUID:", id, "length:", len(id))
	a := "12345#$%^&*67890qwerty/;'~!@uiopasdfghjklzxcvbnm,.()_+·><"
	id = shortuuid.NewWithAlphabet(a)
	fmt.Println("shortUuid2:", id, "length:", len(id))
}
func nanoidTest() {
	s, _ := nanoid.Standard(21)
	id := s()
	fmt.Println("nanoid:", id, "length:", len(id))
	c, _ := nanoid.CustomASCII("0123456789", 12)
	id = c()
	fmt.Println("nanoid2:", id, "length:", len(id))
}
func ulidTest() {
	t := time.Now().UTC()
	e := rand.New(rand.NewSource(t.UnixNano()))
	id := ulid.MustNew(ulid.Timestamp(t), e)
	fmt.Println("ulid:", id.String(), "length:", len(id.String()))
}
func xidTest() {
	id := xid.New()
	fmt.Println("xid:", id, "length:", len(id))
}
func ksuidTest() {
	id := ksuid.New()
	fmt.Println("ksuid:", id, "length:", len(id))
}
func sqidsTest() {
	s, _ := sqids.New()
	id, _ := s.Encode([]uint64{1, 2, 3})
        fmt.Println("sqids:", id, "length:", len(id))
        s, _ := sqids.New(sqids.Options{
		MinLength: 10,
	})
	id, _ := s.Encode([]uint64{1, 2, 3})
        fmt.Println("sqids2:", id, "length:", len(id))
	numbers := s.Decode(id)
        fmt.Println("sqids numbers:", numbers)
}