问题

什么时候需要分库分表?

答案

1. 核心判断标准

分库分表是一项复杂的架构决策,需要在收益与成本之间权衡。以下是常见的判断指标:

维度 临界值参考 说明
单表数据量 500万 - 1000万行 超过后查询性能明显下降,索引效率降低
数据库连接数 接近最大连接数的80% MySQL默认151,达到瓶颈需要分库
单库QPS 3000 - 5000 单库并发压力过大,响应时间变长
磁盘容量 达到单机容量的70% 存储空间不足,需要横向扩展
单表文件大小 10GB以上 影响备份恢复、DDL操作的执行时间

2. 需要分库分表的典型场景

场景1:单表数据量过大

// 典型案例:订单表
// 日订单量:100万
// 保留时长:3年
// 预估数据量:100万 × 365 × 3 ≈ 10亿条

// 问题表现:
// 1. 分页查询耗时:SELECT * FROM order LIMIT 10000000, 20;  // 耗时>5秒
// 2. 索引失效:B+树层级过深,索引查询效率降低
// 3. 统计查询慢:COUNT(*)、聚合查询全表扫描

解决方案:水平分表,按时间或ID范围拆分

场景2:并发写入压力大

// 典型案例:秒杀系统
// 峰值QPS:10000
// 单库最大QPS:3000

// 问题表现:
// 1. 数据库连接池耗尽
// 2. CPU使用率持续100%
// 3. 慢查询日志大量堆积
// 4. 锁等待时间增加

解决方案:水平分库,将并发压力分散到多个数据库实例

场景3:业务复杂度高,耦合严重

// 典型案例:电商系统
// 单库包含:用户、订单、商品、库存、支付、物流等30+张表

// 问题表现:
// 1. 不同业务团队开发冲突
// 2. 某个模块故障影响整个系统
// 3. 数据库备份时间过长
// 4. 无法针对不同业务做精细化优化

解决方案:垂直分库,按业务领域拆分

场景4:读写分离后仍然性能不足

// 已实施读写分离,但:
// 1. 从库数量已达5个,同步延迟仍然明显
// 2. 主库写入压力仍然过高
// 3. 单表数据量过大,读从库也很慢

解决方案:在读写分离基础上,进一步实施分库分表

3. 何时不需要分库分表

情况 建议
数据量小于500万 优先优化索引、SQL、缓存
并发不高 通过垂直扩展(升级硬件)解决
业务简单 保持单库单表,降低维护成本
团队技术储备不足 先通过读写分离、缓存等简单方案过渡

4. 分库分表的时机选择

// 推荐的演进路线:
// 阶段1:单库单表 → 优化索引、SQL
// 阶段2:读写分离 → 解决读压力
// 阶段3:引入缓存 → 降低数据库压力
// 阶段4:垂直分库 → 按业务拆分
// 阶段5:水平分表 → 解决单表数据量问题
// 阶段6:水平分库 → 解决并发和存储问题

// 实际决策示例
public class ShardingDecision {

    public boolean needSharding(TableMetrics metrics) {
        // 满足任一条件即考虑分库分表
        return metrics.getRowCount() > 10_000_000           // 数据量超1000万
            || metrics.getTableSizeGB() > 10                 // 表文件超10GB
            || metrics.getQps() > 5000                       // QPS超5000
            || metrics.getConnectionUsageRate() > 0.8        // 连接使用率超80%
            || metrics.getSlowQueryRate() > 0.1;             // 慢查询率超10%
    }
}

5. 决策前的准备工作

在决定分库分表前,务必做好以下评估:

  1. 容量规划
    // 预估未来1-3年的数据增长量
    long dailyGrowth = 1_000_000;      // 日增长100万
    int retentionDays = 365 * 3;        // 保留3年
    long totalRows = dailyGrowth * retentionDays;  // 约10亿
    
    // 计算需要的分片数
    long maxRowsPerShard = 10_000_000;  // 单表最大1000万
    int shardCount = (int) Math.ceil(totalRows / (double) maxRowsPerShard);
    // 结果:需要100个分片
    
  2. 成本评估
    • 开发成本:改造应用代码、中间件集成
    • 运维成本:监控、备份、扩容的复杂度增加
    • 测试成本:需要更全面的测试覆盖
  3. 风险评估
    • 数据迁移风险:历史数据如何平滑迁移
    • 兼容性风险:现有业务逻辑是否需要大幅改造
    • 回滚方案:分库分表后如何回退

6. 核心要点总结

  1. 分库分表不是银弹,应该是在其他优化手段(索引优化、读写分离、缓存)无法解决问题时的选择
  2. 单表数据量超过1000万或单库QPS超过5000时,应认真考虑分库分表
  3. 提前规划比临时抱佛脚更重要,在业务初期就应考虑扩展性
  4. 先垂直后水平:优先按业务垂直拆分,再根据数据量水平拆分
  5. 评估成本:分库分表会带来复杂度上升,需要团队有相应的技术储备和运维能力