Bohr-L Bohr-L
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

刘博

I'm a slow walker, But I never walk backwards.
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 数据处理与存储类

  • Spring 生态类

  • 缓存问题类

  • 多线程类

  • JVM 类

  • MySQL 类

    • MySQL 为什么一定要有一个主键
    • MySQL 中的 RR 隔离级别,到底有没有解决幻读问题
    • MySQL 的行级锁到底锁的是什么东西?
    • 存储 MD5 值应该用 VARCHAR 还是用 CHAR?
    • 数据库的三范式是什么?
    • 说说 InnoDB 与 MyISAM 的区别
    • drop、truncate、delete 的区别
    • 聊一聊数据库事务机制
    • 聊一聊 MySQL 中的关联查询
    • 事务隔离级别有哪些?MySQL 的默认隔离级别是什么
    • 分库分表之后,id 主键如何处理?
      • 说说在 MySQL 中一条查询 SQL 是如何执行的?
      • 讲解下 DDL、DML、DCL
      • 存储过程和触发器的作用
      • MySQL 如何行转列和列转行
      • 如何查看 SQL 的执行计划
      • union 和 unionAll 的区别
      • having 和 where 的区别
      • 常见的索引原则
      • MySQL 中的 IN 和 EXISTS 子句有什么区别?
      • MySQL 如何处理 NULL 值,对性能有什么影响?
      • 如何在 MySQL 中处理和避免全表扫描?
      • MySQL 中的表空间是什么,它的作用是什么?
      • 在 MySQL 中,如何优化 ORDER BY 查询?
    • Java 8 + 特性类

    • 其他技术类

    • 常见面试题
    • MySQL 类
    刘博
    2025-12-29
    目录

    分库分表之后,id 主键如何处理?

    分库分表后,主键需满足 “全局唯一” 和 “有序性”(便于排序、分页),传统自增主键(单表自增)会因多表并行生成导致重复,常用解决方案如下:

    # 1. 方案 1:UUID/GUID(全局唯一标识符)

    • 原理:通过算法生成 128 位(UUIDv4)的全局唯一字符串(如550e8400-e29b-41d4-a716-446655440000),无需数据库干预,直接在应用层生成;
    • 优点:
      • 实现简单(Java 中UUID.randomUUID()直接生成);
      • 无中心化依赖,分库分表节点可独立生成,支持水平扩展;
    • 缺点:
      • 无序性:UUID 是随机字符串,无法保证递增,插入数据库时会导致索引碎片(InnoDB 聚簇索引无序插入,效率低);
      • 占用空间大:128 位字符串(36 字符),比整数主键占用更多存储和索引空间;
    • 适用场景:对主键有序性无要求的场景(如日志表、标签表)。

    # 2. 方案 2:雪花算法(Snowflake)

    • 原理:生成 64 位长整型(Long)主键,结构如下(可自定义分段):
      • 1 位符号位(固定 0,确保正数);
      • 41 位时间戳(毫秒级,可使用 69 年);
      • 10 位机器 ID(支持 1024 个节点,适配分库分表的多个节点);
      • 12 位序列号(每个节点每毫秒可生成 4096 个 ID,避免并发冲突);
    • 优点:
      • 全局唯一:时间戳 + 机器 ID + 序列号组合,无重复;
      • 有序递增:按时间戳递增,插入数据库时索引效率高(聚簇索引有序插入);
      • 性能高:本地生成,无网络开销,支持高并发(每秒可生成百万级 ID);
    • 缺点:
      • 依赖系统时间:若系统时间回拨(如服务器时钟校准),可能生成重复 ID(需通过算法优化,如记录最后生成时间,回拨时等待或报错);
      • 需配置机器 ID:需确保分库分表的每个节点机器 ID 唯一(如通过配置文件或注册中心分配);
    • 适用场景:高并发、对主键有序性有要求的场景(如订单表、用户表),是分库分表的首选方案。

    # 3. 方案 3:数据库自增主键(号段模式)

    • 原理:搭建独立的 “主键生成数据库”,通过号段分配(如每次给分库分表节点分配一段 ID 区间,如 1-10000),节点在区间内自增生成主键,区间用完后再申请新号段;
    • 实现示例:
      • 主键生成表(id_generator):存储表名、当前最大 ID、号段长度(如table_name='order', current_max_id=10000, step=10000);
      • 分库分表节点 A 申请号段:获取 1-10000,生成 ID 时从 1 自增到 10000;
      • 节点 A 号段用完后,再次申请新号段(10001-20000);
    • 优点:
      • 有序递增:符合数据库主键的递增特性,索引效率高;
      • 无重复:号段全局唯一,节点间无重叠;
    • 缺点:
      • 依赖中心化服务:主键生成数据库是单点(需部署主从集群保证高可用);
      • 性能瓶颈:高并发下,号段申请可能成为瓶颈(可通过增大号段长度减少申请次数);
    • 适用场景:对主键有序性要求高、并发量中等的场景(如电商订单表)。

    # 4. 方案 4:复合主键(分表键 + 自增主键)

    • 原理:主键由 “分表键 + 单表自增主键” 组成,确保全局唯一(分表键不同,即使单表自增主键重复,复合主键也唯一);
    • 示例:分表键为user_id%8(分 8 张表),单表自增主键为id,复合主键为user_id%8 + "_" + id(如0_1001、1_1001);
    • 优点:实现简单,无需额外组件;
    • 缺点:
      • 主键长度长(字符串类型),索引效率低;
      • 无序性:不同分表的自增主键独立,复合主键整体无序;
    • 适用场景:分表键固定、对主键性能要求不高的场景(如用户收货地址表)。

    # 5. 方案对比与选择

    方案 全局唯一 有序性 性能 依赖组件 推荐度
    UUID/GUID 是 否 高 无 ★★★☆☆
    雪花算法 是 是 高 无(需配置机器 ID) ★★★★★
    数据库自增(号段模式) 是 是 中 主键生成数据库 ★★★★☆
    复合主键 是 否 中 无 ★★★☆☆
    • 首选:雪花算法(兼顾性能、唯一性、有序性,无中心化依赖);
    • 次选:号段模式(适合对有序性要求极高、需避免时间回拨风险的场景);
    • 慎用:UUID/GUID(仅适合对有序性无要求的场景)、复合主键(仅适合简单分表场景)。

    上次更新: 12/30/2025
    事务隔离级别有哪些?MySQL 的默认隔离级别是什么
    说说在 MySQL 中一条查询 SQL 是如何执行的?

    ← 事务隔离级别有哪些?MySQL 的默认隔离级别是什么 说说在 MySQL 中一条查询 SQL 是如何执行的?→

    最近更新
    01
    CPU 使用率较高排查和解决
    12-29
    02
    JVM OOM 问题如何排查和解决
    12-29
    03
    接口防刷怎么实现?
    12-29
    更多文章>
    Theme by Vdoing | Copyright © 2025-2026 Bohr-L's note
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式