Skip to content

P31 分库分表 id 冲突解决方案 ​

面试题:分库分表后,多个库/表各自生成主键,怎么避免 ID 冲突?

核心问题 ​

单库自增主键在分库分表后失效:两个库都从 1 自增,会生成重复 ID。

常见方案对比 ​

1. 数据库分段/步长自增 ​

text
库1:起始 1,步长 4:1, 5, 9, 13...
库2:起始 2,步长 4:2, 6, 10, 14...

配置 auto_increment_offset + auto_increment_increment。

  • 优点:简单、无额外组件;
  • 缺点:扩容要改步长(老数据 ID 段与新步长冲突),适合表数量固定的场景。

2. 号段模式(推荐) ​

用一个发号表批量取号段:

sql
UPDATE id_generator SET max_id = max_id + 1000 WHERE biz_type = 'order';
SELECT max_id - 1000, max_id FROM id_generator WHERE biz_type = 'order';

服务拿到 [10001, 11000] 号段在本地内存分配,用完再取下一段。

  • 优点:性能高(一次取号服务 N 次用)、实现简单;
  • 缺点:依赖 DB,号段用完前要提前预取。

3. Redis 原子自增 ​

INCR id:order 获取全局唯一 ID。

  • 优点:快、简单;
  • 缺点:依赖 Redis 可用性,纯自增可预测(不适合订单号暴露场景)。

4. UUID ​

UUID.randomUUID()。

  • 优点:本地生成、无依赖;
  • 缺点:无序(作主键会导致 B+ 树页分裂、性能差)、太长(36 字符)。

5. Snowflake(雪花算法)— 生产最常用 ​

text
64 位 = 1位符号位 + 41位时间戳 + 10位机器ID + 12位序列号
  • 趋势递增、分布式无中心、每秒单机约 409.6 万个 ID;
  • 注意点:时钟回拨要处理(等待/拒绝)、机器 ID 唯一性、序列号溢出;
  • 变体:美团 Leaf(号段 + 雪花)、百度 UidGenerator。

6. 时间戳 + 随机/业务组合 ​

如 yyyyMMddHHmmss + 随机数,简单但不保证绝对唯一,要配唯一索引兜底。

方案选型建议 ​

场景推荐
订单号等需趋势递增、高性能Snowflake / 号段
简单业务、表固定分段自增
无中心化诉求、容忍无序UUID(避免做主键)
高频短号(验证码/短链)Redis INCR

一句话总结 ​

分库分表后 ID 冲突用"号段模式 / Snowflake 雪花算法"解决最主流:号段靠 DB 发号表批量取、雪花靠时间戳+机器ID+序列号本地生成;UUID 无序、Redis 有依赖,按场景选择。

基于 VitePress 重建