关系型数据库的分库分表
一、 核心前置观念:架构师的克制
“在我的认知里,分库分表是关系型数据库性能优化的‘最后一招’,不到万不得已绝不轻易使用。”
在考虑分库分表之前,我一定会先穷尽以下手段:
- SQL 与索引优化:消灭慢查询。
- 引入缓存:用 Redis 挡住高频读请求。
- 读写分离:主库抗写,配置多个从库抗读。
- 硬件升级:升配云数据库的 CPU、内存或采用 SSD。
- 冷热数据分离:把半年前的历史数据迁移到归档表或 HBase/ES 中。
只有当以上手段都无法解决瓶颈时,我才会祭出“分库分表”这个大杀器。
二、 什么时候分表?什么时候分库?(触发条件)
很多人分不清这两者的根本区别。你需要精准地点出它们解决的底层物理瓶颈是不同的。
1. 什么时候考虑【分表】? -> 解决“存储与磁盘 I/O”瓶颈
- 底层原理:MySQL InnoDB 引擎的索引是 B+ 树。当单表数据量过大时,B+ 树的层级会变高(通常超过 3 层),导致一次查询需要经历多次磁盘 I/O,性能出现断崖式下跌。
- 量化指标:业界通常的经验值是,当单表数据量达到 500万到 2000万行,或者单表物理文件大小超过 2GB 时。
- 业务表现:即便索引打满,简单的
SELECT依然很慢;DDL 操作(如加字段)极度缓慢甚至锁表。 - 一句话总结:数据量太大,树太高,查得慢,就分表。
2. 什么时候考虑【分库】? -> 解决“计算与连接数”瓶颈
- 底层原理:单个物理数据库服务器的 CPU、内存和网络带宽是有限的。同时,数据库的最大连接数(
max_connections)也存在上限。 - 量化指标:当数据库服务器的 CPU 长期飙升至 80% 以上,或者并发请求极高,导致数据库连接池频繁被打满、请求排队超时。
- 业务表现:双十一大促等高并发场景下,单台数据库实例直接被流量打挂。
- 一句话总结:并发量太高,CPU 扛不住,连接数不够,就分库。
三、 分库分表的收益与惨痛代价
面试官最喜欢听的是“代价”,因为这证明你真正踩过坑。
🟢 带来的好处 (收益)
- 突破单机物理极限:理论上可以支撑无限大的数据量和并发量。
- 故障隔离:如果某个分库所在的物理机宕机,只会影响该库对应的那部分用户,系统依然具备部分可用性。
🔴 带来的坏处 (填坑指南 - 必须背熟的考点)
- 分布式事务之痛:原本一个
@Transactional就能解决的本地事务,现在跨了多个物理库。必须引入 Seata (AT/TCC 模式) 或基于 MQ 的最终一致性方案,系统复杂度成倍增加。 - 跨库 JOIN 的灾难:你无法再对跨不同库的表执行
JOIN。
- 解法:字段冗余设计(宽表)、应用层在内存中拼接,或者使用 ShardingSphere 的“绑定表/广播表”。
- 全局分页与排序的性能黑洞:比如
SELECT * FROM order ORDER BY time LIMIT 1000000, 10。中间件必须去所有分表里各自查出前 1000010 条数据,拿到内存中汇总排序后再取 10 条,这会瞬间打爆应用内存(OOM)。
- 解法:禁止跳页查询(只允许上一页/下一页),或者将查询逻辑完全外包给 Elasticsearch。
- 全局唯一 ID 失效:自增主键互相冲突。
- 解法:必须引入雪花算法(Snowflake)、Redis 自增或美团 Leaf 等分布式 ID 生成器。
四、 基于 ShardingSphere 的技术落地细节(硬核环节)
如果你在简历里写了 ShardingSphere,你需要展现出对它核心概念和执行流的掌控力。在 Java 后端开发中,我们最常用的是 ShardingSphere-JDBC(以轻量级 Jar 包形式嵌入业务代码)。
1. 核心模型(向面试官展示你懂它的 DSL)
- 逻辑表 (Logic Table):代码里写的名字,比如
t_order。 - 真实表 (Actual Table):物理存在的表,比如
t_order_0到t_order_3。 - 数据节点 (Data Node):数据源与物理表的组合,比如
ds_0.t_order_1。
2. 分片算法设计(核心考点)
面试时你需要给出一个具体的策略,比如“基于 user_id 进行分片”:
-
标准分片策略 (Standard Sharding):这是最常用的。
-
分库算法:
user_id % 2(决定去ds_0还是ds_1)。 -
分表算法:
(user_id / 2) % 2(决定去该库下的t_order_0还是t_order_1)。 -
Hint 分片策略 (影子路由):(如果你能讲出这个,面试官绝对会眼前一亮)
-
业务痛点:有些报表查询 SQL 里压根没有
user_id怎么办? -
解法:通过
HintManager.getInstance().addDatabaseShardingValue(...)在 ThreadLocal 中手动注入分片键,强制告诉 ShardingSphere 去哪个库查。
3. ShardingSphere 解决 JOIN 的高级特性
- 绑定表 (Binding Table):比如订单表
t_order和订单明细表t_order_item。只要它们的分片键和算法一模一样,我们就在配置里把它们声明为“绑定表”。这样在执行 JOIN 时,ShardingSphere 就知道它们必定在同一个物理库里,从而避免了恐怖的笛卡尔积查询。 - 广播表 (Broadcast Table):比如全国省份字典表。我们在配置里声明它为广播表,此时任何对它的
INSERT/UPDATE,ShardingSphere 都会自动拦截并复制到所有的物理库中。这样业务查的时候,直接和本地库的订单表做 JOIN 即可。

浙公网安备 33010602011771号