在分布式业务场景中,单库自增主键很容易在分库分表或多实例写入时发生冲突。雪花算法通过时间戳加机器位生成 ID,但当系统 ID 增长缓慢或遇到时钟回拨时,依然可能重复。本文从 SQL 与中间件配合的角度,介绍几种可替代雪花算法、且能稳妥处理慢慢增长 ID 的主键方案。

为什么雪花算法并非万能
雪花算法依赖机器时钟,若服务器时间回拨,可能生成与之前相同的 ID。另外在低并发、ID 慢慢增长的环境下,时间戳低位长期不变,也会让 ID 规律性强、易被推测。因此我们需要更贴合 SQL 存储模型的替代做法。
方案一词段模式(Segment)
号段模式由数据库统一分配 ID 区间,应用本地缓存后按需使用。即使 ID 增长很慢,也能通过批量取号避免频繁访问数据库。
建表与取号 SQL
CREATE TABLE id_segment (
biz_tag VARCHAR(32) PRIMARY KEY,
max_id BIGINT NOT NULL,
step INT NOT NULL
);
-- 初始化业务标签
INSERT INTO id_segment (biz_tag, max_id, step) VALUES ('order', 0, 1000);
-- 获取下一个号段(应用端事务内执行)
UPDATE id_segment
SET max_id = max_id + step
WHERE biz_tag = 'order';
SELECT max_id, step FROM id_segment WHERE biz_tag = 'order';
应用拿到 max_id 与 step 后,在内存中从 (max_id - step + 1) 到 max_id 依次分配,用完再取新段。即使 ID 慢慢增长,数据库写入压力也很低。
方案二UUID 与数据库结合
UUID 能保证全局唯一,但无序导致 B+ 树索引分裂。可在 SQL 中把 UUID 作为逻辑主键,另用自增列做物理聚簇键。
CREATE TABLE user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, uuid CHAR(36) NOT NULL UNIQUE, name VARCHAR(50) );
这样写入时聚簇索引仍线性增长,避免页分裂,同时业务层用 uuid 做对外 ID,规避慢慢增长带来的预测问题。
方案三Redis 原子自增
利用 Redis 的 INCR 生成趋势递增 ID,再写入 SQL。适合跨服务且不愿引入雪花算法的系统。
# Redis 命令行取 ID INCR global:order:id
应用将返回的数字作为主键插入数据库。由于 Redis 单线程原子性,不会重复;ID 虽慢慢增长但绝对单调,方便 SQL 索引。
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 号段模式 | 数据库压力小,ID 有序 | 需额外表与取号逻辑 |
| UUID 结合自增 | 实现简单,全局唯一 | UUID 占空间,索引稍弱 |
| Redis 自增 | 跨服务易用,单调 | 依赖 Redis 可用性 |
总结
当 SQL 系统面临慢慢增长的 ID 且要避开主键冲突时,不必拘泥于雪花算法。根据并发量、基础设施依赖,选择号段模式、UUID 辅助或 Redis 自增,都能在保障唯一的前提下让主键策略更稳健。
snowflake_algorithmauto_incrementdistributed_id修改时间:2026-07-30 07:15:20