面试记录 2026-09-23
题目:分表算法都有哪些?
难度:medium
标签:db/sharding, general/knowledge, difficulty/medium
评分:⭐⭐☆☆☆(2/5)
我的回答
分表算法,分表算法主要的作用就是为了把数据件数据划分到不同的区间。核心的其实范围选定,一定的范围内,比如说一年的数据画一个,也就是范围区间去选定。然后另外就是哈希,一致性哈希,把某些数据 ID 的数据打到同一个分片上,这时候实现数据分表。常见的就这两种,因为分表是要考虑未来的数据,所有都能在一个位置找到,而不能随机去选。
点评
优点:
- 覆盖最常用的两种:范围(Range)+ 哈希(Hash),并点名一致性哈希
- 提到分表算法的底层诉求:数据路由可预测,不能随机选
不足:
- 只覆盖 2 种,不完整——还缺 List、Key、基因法、Range+Hash 组合、Mod 取模
- 每种算法的适用场景和代价完全没讲
- 漏了核心概念"基因法"(Order_id 嵌 buyer_id 分片位),电商必备加分点
- 没讲扩容代价差异:Range 迁旧数据、Hash 几乎全表迁、一致性哈希只迁 1/N
- 漏了组合方案:先 hash 库 + 库内再 range 表
补充:
- 六种常见算法:Range、Mod、一致性哈希、Gene Method(基因法)、List、Key
- 关键权衡:扩容频繁→一致性哈希/基因法;归档频繁→Range;极致均匀→Mod;
- 组合方案:分库按一致性哈希、分表按 range,兼顾扩容与归档
完整讲解
第一部分:知识重点剖析
核心考点定位:能否系统性列出主流分片算法,并说清各自的适用场景、扩容代价和典型组合。
知识点拆解:
- 六大主流分片算法:
- Range(范围分片):按区间切分,如按月、按季度、按编号区间
- Mod(取模分片):
shard = hash(key) % N,最经典也最均匀
- 一致性哈希(Consistent Hash):环形映射 + 虚拟节点,扩容只迁 1/N
- Gene Method(基因法):主键低位嵌入分片位,如 order_id 的后 4 位是 hash(buyer_id) % 16
- List(枚举分片):按枚举值映射,如 country_code、tenant_id
- Key(内置哈希):MySQL 分区场景,用
KEY(col) 让引擎自己哈希
- 每种算法的适用场景和代价:
- Range:适合时序数据、按月归档;缺点是写热点集中在新片、扩容要迁旧数据
- Mod:分布最均匀,但扩容要重映射几乎全部数据(N→N+1 时约 N/(N+1) 数据要迁)
- 一致性哈希:扩容/缩容只影响相邻节点,迁移 1/N;加虚拟节点(每物理节点 100-200 个虚拟点)解决负载不均
- 基因法:主键即路由键,写入零成本路由,天然支持扩容(新分片从 0 开始);缺点是主键要占用位数
- List:适合离散值映射(国家、租户、机房),业务可解释性强
- 扩容代价对比:
- Mod:N→N+1 时约 N/(N+1) 数据要迁 → 16→17 时 93.75% 数据要动
- 一致性哈希:扩容只迁 1/(N+1) 数据;缩容也只影响相邻节点
- Range:扩容时把旧区间数据分批迁移到新区间
- 基因法:新数据自动落到新分片,历史数据不迁
- 组合方案(工程实践关键):
- 分库按一致性哈希、分表按 Range:分库层解决扩容均衡,分表层解决时序归档
- 分库按 Gene、分表按 Mod:基因法保证路由一致,库内取模保证均匀
- 两级 Hash:分库 = hash(user_id) % 8,分表 = hash(order_id) % 16 → 8 库 × 16 表 = 128 分片
- 常见误区:
- 不要为了扩容选一致性哈希:如果分片数一开始就选 2 的幂(8、16、32)并且很少扩,Mod 完全够用
- 基因法要求主键能改:如果是自增 ID 就要换成雪花算法之类的分布式 ID
- List 不适合高频枚举值:一旦枚举值增加,涉及跨片迁移
第二部分:考察方向与延伸递进
考察方向:
- 深度:能否说清每种算法的底层原理(尤其是一致性哈希环形 + 虚拟节点、基因法嵌分片位)
- 广度:能否关联扩容代价、主键设计、二级路由等相邻知识
- 应用:能否为具体业务组合多种算法
延伸递进面试题:
- 一致性哈希的虚拟节点解决什么问题?没有虚拟节点会怎样?
- 解答要点:无虚拟节点时物理节点少会导致负载不均;虚拟节点把环形映射更细粒度,每个物理节点映射 100-200 个虚拟点
- 基因法如何在主键中嵌入分片位?举个例子说明。
- 解答要点:雪花算法的 64 位 ID 中,低 4 位(16 分片)存 hash(buyer_id) % 16;查询时截取低位直接路由
- N→N+1 扩容时,Mod、Range、一致性哈希分别要迁多少数据?
- 解答要点:Mod 约 N/(N+1) 全表迁;Range 只迁新增区间;一致性哈希约 1/(N+1)
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,分片算法主流有六类,我用"适用场景 + 扩容代价"两条主线来说。
第一类:Range(范围分片)。按区间切,比如按月、按季度、按 ID 编号区间。最适合时序数据——比如订单按创建月份分区,最近一个月一个分片。优点是归档方便(DROP PARTITION)、区间查询命中单片;缺点是写热点集中在新分片,扩容时旧区间要迁移。
第二类:Mod(取模分片)。shard = hash(key) % N,最经典的算法,分布最均匀。但它有个致命问题:扩容代价巨大。N 从 8 变 9,几乎 8/9(88.9%)的数据都要重新映射到新分片。所以 Mod 适合分片数一开始就定死的场景,我们一般会选 2 的幂(8、16、32、64)预留扩容空间。
第三类:一致性哈希。把哈希值映射到一个 2^32 的环上,key 顺时针找到第一个节点归属。扩容时只迁移相邻节点上的 1/N 数据,8→9 扩容时只影响 1/9 的数据,比 Mod 好太多。缺点是节点少时负载不均,所以要加虚拟节点——每个物理节点在环上映射 100-200 个虚拟点,让哈希分布更均匀。适合经常扩容/缩容的场景。
第四类:基因法(Gene Method)。这是电商场景的绝招。核心思想是在主键里嵌入分片位——比如订单号用雪花算法生成 64 位,低 4 位存 hash(buyer_id) % 16,这样查询订单时截取低 4 位直接路由到对应分片,不需要额外查 buyer_id。扩容时新分片从 0 开始,历史数据不用迁。缺点是主键要占用位数,且要求主键能改(自增 ID 不行,得用雪花算法)。
第五类:List(枚举分片)。按枚举值映射,比如 tenant_id、country_code、机房码。适合 SaaS 多租户场景,每个租户一个分片,业务可解释性最强。缺点是枚举值多了以后迁移麻烦。
第六类:Key(内置哈希)。这是 MySQL 分区用的,你不用管哈希细节,PARTITION BY KEY(col) 引擎帮你算。主要在分区场景用,跨库分片很少见。
组合方案是工程实践的关键。我们项目里常用的组合是"分库按一致性哈希 + 分表按 Range":分库层用一致性哈希保证扩容均衡(跨机器的问题),分表层按月分片解决时序归档。这样扩容时只需在库层加机器,归档时只需在表层 DROP PARTITION,两个问题解耦。
选型原则:
- 扩容频繁 → 一致性哈希 或 基因法
- 归档频繁 → Range
- 追求极致均匀且扩容少 → Mod + 2 的幂
- 多租户 → List
- 分片键就是主键 → 基因法
一句话总结:没有最好的算法,只有最适合业务生命周期的组合。一开始就要评估未来 3-5 年的扩容计划,选一个扩容代价最小的算法组合。