framework
framework/mysql/ops/sharding-key-choice.md
high
mysql-sharding-key-choice
分库分表拆分键选择 — 选高频查询条件且分布均匀的列做 sharding key,避免热点与跨片查询,跨片 JOIN/聚合/分布式事务是分片最大代价。Use when 单表过大要分库分表 / 选拆分键 / 评审分片方案的跨片查询时。
分库分表拆分键sharding key分片键跨片查询热点分片shardingsphere
paths
*.sql*.java*.yml*.xml
MySQL · 分库分表拆分键选择
本条只管「分片时拆分键怎么选」。要不要分片(vs 加索引/读写分离/换 PG)是选型问题,见
../../../tech-selection/database/index.md;分片后主键生成见distributed-id.md。
前提:先别急着分
分库分表是最后手段,代价大。先确认已穷尽:索引优化、读写分离、归档冷数据、上缓存。单表数据量到千万级且仍是瓶颈才考虑。
拆分键选择原则
| 原则 | 说明 |
|---|---|
| 高频查询条件 | 拆分键应是绝大多数查询的 WHERE 条件,否则查询要扫所有分片 |
| 分布均匀 | 值要散得开,避免某片数据/流量畸大(热点片) |
| 少变更 | 拆分键值一旦定下尽量不改(改了要迁移数据到别的片) |
| 业务内聚 | 同一业务实体的数据尽量落同片,减少跨片操作 |
常见选择:用户类业务用 user_id;订单按 user_id 分(用户查自己订单不跨片)而非 order_id。
分片的最大代价:跨片操作
| 操作 | 问题 | 缓解 |
|---|---|---|
| 跨片 JOIN | 无法在单库 join | 冗余字段/宽表、应用层聚合、绑定表同片 |
| 跨片聚合/排序 | 要查所有片再合并 | 中间件归并、预聚合表 |
| 跨片事务 | 退化为分布式事务,重 | 尽量让一笔业务落单片,避免 |
| 非拆分键查询 | 广播到所有片 | 建「索引表」映射其它键→拆分键 |
落地
- 中间件:
ShardingSphere(Java 生态主流),定分片策略与拆分键。 - 分片数预留扩容(如按一致性哈希或预分够槽位),避免后续二次拆分。
反例
❌ 订单表按 order_id 分片,但 90% 查询是"查某用户的订单"
→ 每次都广播到所有分片,分片反而更慢
✅ 按 user_id 分片,用户查自己订单命中单片;另建 order_id→user_id 索引表兜跳查
自检
- [ ] 是否已穷尽索引/读写分离/归档/缓存,确认非分片不可?
- [ ] 拆分键是绝大多数查询的 WHERE 条件、分布均匀、少变更?
- [ ] 主要业务操作能落单片,跨片 JOIN/事务降到最少?
- [ ] 非拆分键的高频查询有索引表或冗余方案,不靠全片广播?
相关
- 父:
./index.md - 兄弟:
distributed-id.md - 选型(要不要分片):
../../../tech-selection/database/index.md