⭐ 推荐:社区规则条款 V1.0

分库分表后如何生成全局唯一且趋势递增的主键?

GJ
GJ 资深会员 👑黑卡会员
发布于 2026-11-01 06:58 ·7 浏览 ·0 回复

学完这篇教程,你将掌握在分库分表场景下解决 ID 冲突和索引性能问题的核心方案,学会使用雪花算法和 Redis INCR 等方法生成全局唯一且趋势递增的主键。

第一步:使用数据库自增 ID(最简单直接)

这一步要做什么:在 MySQL 等数据库表中直接设置主键为自增模式,利用数据库自身的计数机制生成 ID。
具体操作:登录 MySQL 客户端,执行 CREATE TABLE user (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50), PRIMARY KEY (id)) ENGINE=InnoDB;。插入数据时不需要手动指定 id,只需执行 INSERT INTO user (name) VALUES ('Tom');,数据库会自动分配一个连续递增的整数。
得到结果:获得一个全局唯一的整数 ID,且 ID 是严格递增的。

注意:这是最简单的方案,但缺点是 ID 全局不唯一(不同库的自增 ID 会重复),且在分库分表后,ID 趋势递增会变成局部递增,会导致后续的 B+ 树索引频繁页分裂,写入性能急剧下降。

第二步:使用 UUID(保证全局唯一但性能差)

这一步要做什么:利用 UUID 算法生成 32 位的十六进制字符串作为主键。
具体操作:在 Java 代码中调用 String uuid = UUID.randomUUID().toString();,或者在 MySQL 中直接使用 SELECT UUID(); 函数。
得到结果:获得一个全局唯一的字符串 ID,绝对不会重复。

注意:UUID 是无序的,存入数据库后会导致 B+ 树频繁的页分裂,写入性能极差,且占用存储空间较大(36 字符),不适合作为主键。

第三步:使用雪花算法(推荐方案)

这一步要做什么:利用 Twitter 开源的雪花算法,通过时间戳、机器 ID 和序列号组合生成 64 位长整型 ID。
具体操作:编写 Java 代码,定义一个包含 workerId(机器 ID,0-31)和 datacenterId(数据中心 ID,0-31)的类,利用 System.currentTimeMillis() 获取当前时间戳,结合位运算拼接 ID。例如:long id = (timestamp << 22) | (workerId << 12) | sequence;。
得到结果:获得一个既全局唯一又趋势递增的长整型 ID,解决了分布式环境下的 ID 冲突问题,且对数据库索引友好。

注意:雪花算法依赖系统时钟,如果服务器时间回拨(如同步时间),会导致生成的 ID 重复或报错,生产环境必须做好时钟校验。

第四步:使用 Redis INCR(高并发场景)

这一步要做什么:利用 Redis 的原子性自增命令,在内存中维护一个计数器,每次获取 ID 后自增 1。
具体操作:连接 Redis,执行 INCR user_id 命令,将返回值作为主键 ID,并设置过期时间(如 24 小时)防止内存泄漏。
得到结果:获得一个全局唯一且严格递增的数字 ID,性能极高。

注意:Redis 是单线程的,性能极高,但它是单点服务,如果 Redis 宕机,服务将无法生成 ID,通常需要引入 Redis 集群或 Sentinel 模式来保证高可用。

小结:分库分表主键生成需满足唯一性和趋势递增两个核心需求。自增 ID 简单但冲突;UUID 唯一但无序影响性能;雪花算法是目前的最佳实践;Redis INCR 适合高并发但对单点故障敏感。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2696.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~