【架构实战】数据库分库分表实战

一、为什么需要分库分表

当数据量超过单机数据库的承载能力时,分库分表成为必然选择:

  • 单库数据量过亿:查询性能急剧下降
  • 单表数据量过大:索引效率降低,DML操作变慢
  • 连接数耗尽:数据库连接成为稀缺资源
  • 存储空间不足:单机的磁盘容量有上限

二、分库分表策略

1. 垂直拆分

按业务将表或库拆分开:

复制代码
原来:用户库(用户表、订单表、支付表)

拆分后:
  用户库(用户表)
  订单库(订单表)
  支付库(支付表)

2. 水平拆分

按数据规则将表拆分:

sql 复制代码
-- 按用户ID取模分表
users_0: WHERE user_id % 4 = 0
users_1: WHERE user_id % 4 = 1
users_2: WHERE user_id % 4 = 2
users_3: WHERE user_id % 4 = 3

3. 常见的分片键选择

分片键 适用场景 注意事项
用户ID 电商、社交 查询需带用户ID
时间 日志、订单 冷数据归档方便
地区 区域性业务 跨区查询困难
哈希 均衡分布 查询复杂度高

三、分库分表中间件

ShardingSphere

yaml 复制代码
# application.yml
spring:
  shardingsphere:
    datasource:
      ds0:
        url: jdbc:mysql://localhost:3306/db0
        driver-class-name: com.mysql.cj.jdbc.Driver
      ds1:
        url: jdbc:mysql://localhost:3306/db1
        driver-class-name: com.mysql.cj.jdbc.Driver
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: order_inline

MyCat

xml 复制代码
    

四、实战代码

Java SDK 使用示例

java 复制代码
// ShardingSphere JDBC
@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        Map dataSourceMap = new HashMap<>();
        dataSourceMap.put("ds0", createDataSource("db0"));
        dataSourceMap.put("ds1", createDataSource("db1"));
        
        ShardingRuleConfiguration config = new ShardingRuleConfiguration();
        config.getTables().add(createTableRule());
        
        return DataSourceFactory.createDataSource(dataSourceMap, config);
    }
}

// 分片键获取
public Long getShardingKey(Order order) {
    return order.getUserId() % 4;
}

五、跨库查询解决方案

1. 禁止跨库JOIN

java 复制代码
// 业务层面解决:先查用户,再查订单
User user = userMapper.selectById(userId);
List orders = orderMapper.selectByUserId(userId);

2. 异构表

sql 复制代码
-- 在订单库冗余用户信息
CREATE TABLE t_order (
    order_id BIGINT,
    user_id BIGINT,
    user_name VARCHAR(50),  -- 冗余字段
    amount DECIMAL(10,2),
    created_at DATETIME
);

3. ES搜索引擎

复制代码
MySQL(分库分表) → 数据同步 → Elasticsearch
                            ↓
                      复杂查询由ES处理

六、分布式ID生成

分库分表后,需要分布式ID:

java 复制代码
// Snowflake算法
public class SnowflakeIdGenerator {
    private final long twepoch = 1288834974657L;
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    
    public synchronized long nextId() {
        long timestamp = timeGen();
        long id = ((timestamp - twepoch) << 22)
                | (datacenterId << 17)
                | (workerId << 12)
                | sequence;
        return id;
    }
}

// 使用
SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
long orderId = idGenerator.nextId();

七、常见问题与解决方案

Q1:扩容时如何迁移数据?

  • 方案1:双写(新老库同时写)
  • 方案2:定时任务迁移
  • 方案3:使用一致性哈希减少迁移量

Q2:如何保证分页查询?

sql 复制代码
-- 反例:深分页问题
SELECT * FROM t_order ORDER BY id LIMIT 1000000, 10

-- 正例:游标分页
SELECT * FROM t_order WHERE id > 1000000 ORDER BY id LIMIT 10

Q3:分布式事务如何处理?

使用 Seata AT 模式或 TCC 模式

八、总结

分库分表是系统扩展的必经之路,但增加了系统复杂度:

  • ✅ 突破单机性能瓶颈
  • ✅ 提高系统可用性
  • ❌ 跨库查询困难
  • ❌ 运维复杂度增加

思考题:你的系统中数据量最大的是哪张表?有没有考虑过分库分表?


个人观点,仅供参考

相关推荐
东方佑16 小时前
FRSM 规模效应与架构对比补充报告
架构
麦聪聊数据17 小时前
数据服务化时代:企业数据能力输出的核心路径
数据库
shushangyun_17 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
隔窗听雨眠17 小时前
大模型加爬虫上篇:技术融合与架构革新
爬虫·架构
DARLING Zero two♡17 小时前
【MySQL数据库】数据类型与表约束
数据库·mysql
曹牧18 小时前
Oracle EXPLAIN PLAN
数据库·oracle
BD_Marathon18 小时前
SQL学习指南——视图
数据库·sql
Vergelight18 小时前
实战拆解|三类RAG架构差异:朴素、进阶、多轮RAG落地选型指南
架构·大模型·aigc·agent·ai产品经理·转行·ai后台设计
活宝小娜18 小时前
mysql详细安装教程
数据库·mysql·adb
贤时间18 小时前
codex 助力oracle ebs 开发
数据库·oracle