← 返回题目列表

分库分表时如何选择分片键?

高频 困难 第 17 / 27 题 更新于 2026/07/28
分片键路由数据倾斜分库分表设计

简化版

分片键要优先选择高频查询必带、基数高、分布均匀、变化少、能承载主要写入和查询路径的字段。选错分片键会导致广播查询、热点分片、跨库 Join 和后续扩容困难。

详细版

好的分片键通常满足这些条件:

  1. 高频查询能带上它,避免全库全表扫描;
  2. 基数足够高,能把数据均匀打散;
  3. 字段稳定,不会频繁变更;
  4. 和业务聚合边界一致,比如订单按 user_idseller_id 组织;
  5. 写入不会集中到少数分片;
  6. 后续扩容、迁移、归档有可操作性。

常见选择:订单 C 端场景常按 user_id,商家后台常按 seller_id,如果订单号里嵌入分片信息,也可以按 order_id 路由。没有完美分片键时,需要配合冗余表、全局索引表、搜索引擎、ES 或查询平台解决非分片键查询。

完整版教学

一、分片键是分库分表的“方向盘”

分库分表之后,请求要先知道去哪个库、哪张表。这个判断所依赖的字段就是分片键。比如订单按 user_id 分片,那么用户查看自己的订单时,系统拿到 user_id 就能直接定位到目标分片。这个查询很轻。

但如果客服只拿 order_no 查询订单,而 order_no 不能推导出分片位置,系统就不知道该去哪里查。它只能把 SQL 发到所有分片,再合并结果。这叫广播查询。分片数少时可能还能忍,分片数一多,广播查询会把一次请求放大成几十次甚至上百次数据库请求。

所以分片键不是随便找个字段取模,它决定了系统未来最舒服的查询路径,也决定了哪些查询会变困难。

二、选择分片键要先看业务访问路径

设计分片键时,第一步不是看字段,而是画出业务查询路径:

  • 用户端:用户查自己的订单、取消订单、查看物流;
  • 商家端:商家查店铺订单、发货、售后;
  • 平台端:客服按订单号查单、风控按手机号查单;
  • 运营端:按时间、地区、类目做统计。

如果最核心流量来自用户端,user_id 可能是更好的分片键,因为大多数请求都带用户身份。如果核心流量来自商家后台,seller_id 可能更合适。若两类流量都很大,就要考虑数据冗余、异构索引或双维度查询模型,而不是幻想一个字段解决所有问题。

面试里经常问“订单表按用户 ID 还是订单 ID 分片”。答案取决于查询入口:按 user_id 分片方便用户维度查询;按 order_id 分片方便订单详情点查;如果订单号设计时包含分片位,就可以让 order_id 也具备路由能力。

三、分片键要兼顾均匀性和局部性

均匀性指数据和请求不要集中在少数分片。比如按省份分片,北上广深可能流量巨大,而一些地区很少,容易倾斜。按性别分片更糟,只有两个值,完全不适合作为分片键。

局部性指同一业务聚合内的数据最好能落在同一个分片,减少跨分片操作。比如用户订单按 user_id 分片,用户的订单列表可以在一个分片内完成;如果随机按订单号打散,一个用户的订单可能散落在所有分片,列表查询就变成跨分片查询。

这两个目标有时冲突。按用户维度有局部性,但超级大客户可能形成热点;按随机订单号很均匀,但用户维度查询会变散。工程上常用的办法是:主链路选择最重要的局部性,非主链路用冗余索引、搜索系统或离线数仓补齐。

四、字段稳定性也非常关键

分片键最好不要变。比如用户手机号、邮箱、地区都可能变化,如果按这些字段分片,一旦字段变了,数据就要跨分片迁移,还要处理迁移期间读写一致性。相比之下,user_idorder_id 这种生成后不变的字段更安全。

还要注意分片键最好在创建数据时就存在。订单创建时一定有用户 ID 和订单 ID;如果某字段要等后续流程才生成,就不适合承担写入路由。

五、没有完美分片键时怎么补救

真实系统往往有多个查询维度,不可能所有查询都带同一个分片键。常见补救方案包括:

  1. 冗余查询表:比如按 user_id 存订单主表,再冗余一张按 order_no 路由的索引表;
  2. 全局索引表:记录 order_no -> shard_id + table_id,点查时先查索引再查主表;
  3. 搜索引擎:复杂条件检索走 Elasticsearch,数据库只承接精确读写;
  4. 数据仓库:运营统计走离线或近实时分析链路,不压在线分片库;
  5. 分片位编码:在订单号里放入时间、机器号、分片号等信息,提高可路由性。

这些方案本质上是在承认:主表只服务最核心路径,其他路径通过异构数据结构解决。

六、分片键选择可以用一张评分表落地

工程评审时,不要只说“感觉 user_id 比较好”。可以给候选分片键做评分。常见维度包括:核心查询是否必带、字段基数是否足够高、数据分布是否均匀、字段是否稳定不变、写入是否会形成热点、是否支持主要列表查询、扩容迁移是否可控、非分片键查询是否有补救方案。

例如订单表候选分片键有 user_idorder_idseller_id。如果 C 端用户订单列表是最大流量,user_id 在核心查询必带和用户聚合上得分高;如果客服按订单号点查很多,order_id 路由能力更强;如果商家后台是核心场景,seller_id 要重点考虑。最后不一定只靠一个字段解决所有问题,可能是主表按 user_id,订单号编码分片位,商家维度用冗余索引或搜索系统。

评分表的价值是把争论从“谁觉得更好”变成“哪个字段更匹配主链路”。分库分表一旦上线,迁移分片键代价巨大,所以前期评审要尽量把未来三到五倍增长、后台查询、客服查询、风控查询都纳入讨论。

七、分片键选错后的补救成本很高

如果分片键选错,最直接的问题是广播查询变多。假设订单按 order_id 随机打散,但用户订单列表只带 user_id,每次列表查询都要扫所有分片。流量上来后,中间件、连接池和数据库都会被放大请求拖垮。

第二个问题是热点。比如按 seller_id 分片,大商家会形成超级分片;按时间分片,最新时间段会承接所有写入;按地区分片,一线城市可能远大于其他地区。热点和倾斜不只是性能问题,还会导致扩容和迁移越来越困难。

第三个问题是业务改造被绑死。分片键如果会变化,比如手机号、地区、状态,数据就可能需要跨分片移动。移动过程中要保证读写一致、唯一约束和索引同步,成本远高于普通字段更新。面试里能讲出“分片键最好稳定不变、创建时就存在、业务聚合内高频必带”,基本就抓住了要害。

八、常见误区与追问

这道题要紧扣「分片键设计」本身回答,不能把它混成泛泛的分库分表套话。面试官通常不是只听定义,而是看你能不能把适用场景、关键流程、失败边界和工程取舍串起来,尤其要说明拆分边界、路由规则、扩容迁移、跨库查询和一致性兜底。

回答层次要讲清的内容容易漏掉的边界
核心结论分片键要兼顾查询命中率、数据均匀性、业务聚合边界、扩容成本和热点风险不要停在名词解释
流程机制梳理核心查询 -> 选择候选分片键 -> 评估均匀性和热点 -> 验证同分片事务 -> 设计辅助索引 -> 预留扩容方案要说清触发点、状态变化、确认点和失败兜底
工程取舍订单按 user_id 分片适合查用户订单,但按 order_id 分片更适合订单详情和订单明细同分片分库分表能扩展容量和吞吐,但会带来路由、事务、Join、唯一约束、扩容和运维复杂度
分片键设计 面试拆解:
1. 梳理核心查询
2. 选择候选分片键
3. 评估均匀性和热点
4. 验证同分片事务
5. 设计辅助索引
6. 预留扩容方案

记忆钩子:先给结论,再拆流程,再讲数字例子和失败边界;回答「分片键设计」时要围绕题目问法收束,不要把相邻概念堆成一段没有重点的名词清单。

  • 误区:分片键只看是否唯一。 唯一不代表查询高频,也不代表分布均匀。
  • 误区:随机 key 最均匀所以最好。 随机会牺牲范围查询、聚合查询和业务同分片能力。
  • 误区:后期可以随便改分片键。 改分片键通常等于大规模迁移,成本很高。
  • 追问:订单系统按什么分片? 看主查询路径,用户订单列表偏 user_id,订单详情和明细聚合偏 order_id。
  • 追问:分片键热点怎么办? 拆桶、复合键、独立分片、缓存或限流。
  • 追问:非分片键查询怎么办? 全局二级索引、搜索系统、冗余读模型或广播小表。

九、加强记忆

分片键选择的核心不是“哪个字段看起来顺眼”,而是“哪个字段能让最大流量、最关键的一组请求稳定命中少量分片”。高频必带、基数高、分布均匀、稳定不变、贴近业务聚合边界,这五点抓住了,分片键设计就不会跑偏。