当单表数据量逼近千万级、单库连接数频繁触顶时,分库分表就不再是“要不要做”的问题,而是“怎么做、用什么做”的问题。面试中,这个话题几乎是大厂后端岗位的必考题,考察点从方案选型一直延伸到分布式事务与扩容。本文从面试视角梳理常见方案,并给出 ShardingSphere 的实战思路。
一、为什么要分库分表
先明确边界:分库分表解决的是单库单表容量与性能瓶颈,不是万能药。触发时机通常有三类信号:
- 数据量:单表超过 500 万~1000 万行,B+ 树索引层数增加,查询明显变慢;
- 连接数:单库连接数打满,应用侧频繁获取连接超时;
- 磁盘与 IO:单机磁盘容量、IOPS 成为写入瓶颈。
面试时如果能主动说出“先优化索引、读写分离、缓存,再考虑分片”,会比直接背方案更加分。
二、常见分片方案对比
1. 垂直拆分
按业务维度把不同表拆到不同库,例如用户库、订单库、商品库。优点是业务解耦、专库专用;缺点是跨库 JOIN 消失,分布式事务变复杂。垂直拆分通常是第一步,成本低、收益直接。
2. 水平拆分
同一张表按规则拆到多个库/表。核心在于分片键的选择:
- 范围分片:按 ID 区间或时间区间。优点是扩容方便、范围查询高效;缺点是热点集中,新数据总落在最后一个分片。
- 哈希分片:如
user_id % 4。优点是数据分布均匀;缺点是扩容需要数据迁移,范围查询要广播到所有分片。 - 一致性哈希:缓解扩容迁移量,但实现复杂度上升,且容易产生数据倾斜。
- 基因法/复合分片:把分片基因嵌入 ID,使订单按 user_id 分片后,order_id 也能定位到分片,避免二次路由。
3. 中间件选型
| 方案 | 代表 | 特点 |
|---|---|---|
| 客户端分片 | ShardingSphere-JDBC | 无代理、性能好,侵入应用 |
| 代理分片 | ShardingSphere-Proxy、MyCat | 对应用透明,多一层网络开销 |
| 云原生 | PolarDB-X、TiDB | 运维托管,成本较高 |
面试常问“JDBC 和 Proxy 怎么选”:追求低延迟、团队能改代码选 JDBC;多语言栈、想对应用透明选 Proxy。
三、分库分表后的棘手问题
这是面试区分度最高的部分,能答出以下几点说明真正落地过:
- 分布式主键:不能再用自增 ID。常见方案有雪花算法(Snowflake)、号段模式(Leaf)、Redis INCR。雪花算法要注意时钟回拨。
- 跨分片查询:分页、排序、聚合需要归并。
LIMIT 100 OFFSET 10000在分片下要改写为各分片取OFFSET+LIMIT再内存归并,深分页性能极差,通常用“上次最大 ID”游标法优化。 - 分布式事务:跨库写入用 Seata AT/TCC 或本地消息表、最终一致性。强一致场景慎用分片。
- 扩容:哈希取模扩容要迁移大量数据。实践上常用成倍扩容 + 双写迁移,或预分片(如先分 1024 张逻辑表,物理机少放几张,扩容只搬逻辑表)。
- 全局唯一性与字典表:小表做广播表,每个库一份,避免跨库 JOIN。
四、ShardingSphere 实战思路
ShardingSphere 是当前国内落地最广的方案,分为 JDBC 和 Proxy 两个产品。以下以 Spring Boot + ShardingSphere-JDBC 为例。
1. 依赖与配置
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://127.0.0.1:3306/order_db0
username: root
password: root
ds1:
jdbc-url: jdbc:mysql://127.0.0.1:3306/order_db1
# 其余同上
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: db-inline
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: table-inline
sharding-algorithms:
db-inline:
type: INLINE
props:
algorithm-expression: ds$->{user_id % 2}
table-inline:
type: INLINE
props:
algorithm-expression: t_order_$->{order_id % 2}
这段配置把 t_order 拆成 2 库 × 2 表。注意分库键用 user_id、分表键用 order_id,是为了让同一用户的订单落在同库、单号又能均匀打散。
2. 分片键与路由
ShardingSphere 的核心是 SQL 解析 → 路由 → 改写 → 执行 → 归并。写 SQL 时要尽量带上分片键,否则会全路由广播,性能急剧下降。面试可举例:WHERE user_id = ? 能精确定位到一个库,WHERE create_time > ? 则会广播到所有分片。
3. 分布式主键
@Bean
public KeyGenerator keyGenerator() {
return new SnowflakeKeyGenerator();
}
配置 key-generator 后,插入时无需手动设置主键,ShardingSphere 自动生成。
4. 读写分离与广播表
- 读写分离:通过
readwrite-splitting规则配置主从,写走主库、读走从库,注意主从延迟下的“写后读”一致性。 - 广播表:字典表配置
broadcast-tables,每个库都存一份,JOIN 时无需跨库。 - 绑定表:分片规则一致的关联表(如
t_order与t_order_item)配置binding-tables,避免笛卡尔积关联。
5. 扩容思路
ShardingSphere 提供 Scaling(原 ElasticJob 生态)做数据迁移,原理是双写 + 存量迁移 + 校验 + 切换。实践中更稳的做法是:
- 新老集群双写,读仍走老集群;
- 用迁移工具同步存量数据并校验;
- 灰度切读,观察无异常后切写;
- 下线老集群。
五、面试答题框架
如果被问“你们怎么做分库分表”,可以按这个结构回答:
- 判断必要性:数据量、QPS、连接数达到什么阈值才做;
- 选型:垂直还是水平、分片键怎么选、JDBC 还是 Proxy;
- 落地:ShardingSphere 配置、分布式主键、广播表、绑定表;
- 踩坑:深分页、跨库 JOIN、分布式事务、扩容迁移;
- 兜底:监控慢 SQL、热点分片、数据倾斜治理。
分库分表本质是用复杂度换扩展性。面试官想听的不是“我用了 ShardingSphere”,而是你理解每一次拆分带来的代价,以及如何用工程手段把代价控制在可接受范围内。
未经允许不得转载:任鹏个人博客 » MySQL 分库分表常见方案与 ShardingSphere 实战思路

