背景
以MySQL为例,单表 > 1000 万行
或单表大小 > 10GB
表现:索引变大、查询变慢、优化无效。
分库分表时机
单表数据量过大
一般经验值:
单表 > 1000 万行
或单表大小 > 10GB
表现:索引变大、查询变慢、优化无效。
读写压力过高,单机扛不住
CPU 持续高负载
IO 等待严重
主从延迟变大
即使加索引、SQL 优化、加缓存也压不住
并发连接数、TPS/QPS 达到单机瓶颈
MySQL 单机连接数、事务处理能力有上限
分库 vs 分表 核心区别
- 分库(Database Sharding)
定义:把多个库分散到不同 MySQL 实例 / 节点上
物理层面:不同IP、端口、进程
解决问题:数据库连接数、CPU、IO、内存等单机性能瓶颈 - 分表(Table Sharding)
定义:把一张大表拆成多张结构相同的小表
物理层面:可以在同一个库,也可以跨库
解决问题:单表数据量过大,导致查询慢、索引膨胀、DDL 卡死
业务有隔离、合规、多地域部署需求
• 多租户隔离
• 按地区 / 业务线分库
• 合规要求数据物理隔离
一、核心触发指标(硬性条件)
| 指标 | 单表/单库警戒线 | 处理建议 |
|---|---|---|
| 数据量 | ≥ 1000万行 | 考虑分表 |
| 磁盘空间 | ≥ 服务器内存的2~3倍 | 紧急分库分表 |
| QPS/TPS | 读写QPS ≥ 5000 | 分库分表 + 读写分离 |
| 连接数 | 活跃连接数 ≥ 最大连接数70% | 分库分散压力 |
| 慢查询比例 | ≥ 5% | 先优化索引/SQL,无效再分表 |
📌 真实案例 :
某电商平台订单表达到800万行 后,
WHERE user_id=xxx查询从50ms升至1200ms ,分表后恢复至60ms。
二、业务场景触发点(软性条件)
1. 高频访问的热点数据
sql
-- 例如用户表被20%头部用户占据80%访问量
SELECT * FROM users WHERE vip_level > 8; -- 每天执行50万次
解决方案 :按vip_level分库,将高等级用户分散到不同库。
2. 业务垂直拆分需求
将单库A按业务类型拆分为三个库
A[单库] --> B[用户库]
A --> C[订单库]
A --> D[商品库]
- 当不同业务线(如用户、订单、支付)互相抢占资源时
- **优势**:故障隔离、独立扩展
#### 3. **地域/时间分片需求**
- 物流系统:按`region_id`分库(华北/华东/华南)
- 日志系统:按`create_time`按月分表(logs_202301, logs_202302)
---
### 三、不该分库分表的场景(警告!)
| **场景** | **风险** | **替代方案** |
| 数据量 < 100万行 | 分片维护成本 > 收益 | 索引优化/读写分离 |
| 事务强一致性要求高 | 分布式事务复杂度爆炸 | 升级硬件/缓存策略 |
| 无分片键的频繁查询 | 全库扫描性能更差 | 建全局二级索引 |
| 团队无分库分表经验 | 可能引发数据错乱 | 用云数据库(如Aurora) |
#### 具体步骤:
1. **先优化后分片**
- 90%的性能问题可通过优化SQL/索引/缓存解决
```sql
-- 反例:未用索引的查询
SELECT * FROM orders WHERE status=1 ORDER BY create_time DESC;
-- 正解:添加联合索引
ALTER TABLE orders ADD INDEX idx_status_time(status, create_time);
- 先读写分离,再分库分表
- 读多写少场景:用MySQL主从复制 + 读负载均衡
- 写压力大:再考虑分库分表