数据库分库分表策略详解 | 含实战代码与应用案例

362 阅读4分钟

数据库分库分表策略详解 | 含实战代码与应用案例

在当今互联网高速发展的背景下,单体数据库已经无法满足大规模系统对性能和可扩展性的需求。为了提升系统的并发能力和稳定性,数据库分库分表成为后端开发中非常关键的一项技术。

一、什么是数据库分库分表?

1. 分库(Database Sharding)

将原本一个数据库中的多个表,分散到多个物理数据库中,每个数据库只负责一部分数据。例如,可以按照用户ID进行哈希取模,将不同用户的数据存储到不同的数据库中。

2. 分表(Table Sharding)

将一张大表的数据按某种规则拆分成多个小表,这些小表可能存在于同一个数据库中,也可能分布在不同的数据库中。

分库解决的是“数据库压力过大”的问题,而分表解决的是“单表容量过大”的问题。

二、常见的分库分表策略

1. 水平拆分(Horizontal Sharding)

水平拆分是将同一张表的不同行数据分布到不同的数据库或表中。适用于数据量大的场景。

示例:按用户ID取模分库
-- 假设我们有4个数据库 db0, db1, db2, db3
-- 用户ID % 4 = 库编号
-- 插入用户ID为1001的用户到 db1
INSERT INTO db1.user (id, name) VALUES (1001, 'Tom');

2. 垂直拆分(Vertical Sharding)

将一张表的字段拆分到不同的表或数据库中,适合某些字段访问频率远高于其他字段的情况。

示例:将用户基本信息和扩展信息拆分
-- 用户基础信息
CREATE TABLE user_base (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100)
);

-- 用户扩展信息
CREATE TABLE user_ext (
    id INT PRIMARY KEY,
    address TEXT,
    profile TEXT
);

3. 分片键(Sharding Key)的选择

分片键决定了数据如何分布。常见的选择有:

  • 用户ID
  • 时间戳
  • 地区
  • 订单号

分片键一旦选定,后续很难更改,因此需要提前规划好业务逻辑。

4. 数据迁移与一致性保障

当数据增长导致分片不够用时,需要进行扩容操作,比如从4个库扩容到8个库。

此时就需要使用一致性哈希算法虚拟节点来减少数据迁移的工作量。

三、应用场景设计:电商订单系统

假设我们要构建一个电商平台,随着用户量和订单量的增长,单一数据库已无法承载大量写入请求。

需求背景:

  • 用户数量:100万+
  • 日均订单量:10万+
  • 查询需求:支持按用户ID查询订单、按时间范围查询订单

架构设计:

  1. 分库策略:按用户ID进行哈希取模,分配到4个数据库
  2. 分表策略:每张订单表按月份再拆分为子表,如 order_202409、order_202410 等
  3. 读写分离:主库写,从库读
  4. 缓存策略:Redis 缓存热点订单

表结构设计示例:

-- 主表
CREATE TABLE order_base (
    order_id BIGINT PRIMARY KEY,
    user_id INT NOT NULL,
    product_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
);

-- 子表(每月一张)
CREATE TABLE order_202409 (
    order_id BIGINT PRIMARY KEY,
    user_id INT NOT NULL,
    product_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
);

Java代码示例:动态路由数据源

// 根据用户ID选择数据库
public String getDatabase(int userId) {
    int dbIndex = userId % 4;
    return "db" + dbIndex;
}

// 根据订单时间选择子表
public String getTableName(Date createTime) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
    return "order_" + sdf.format(createTime);
}

// 使用MyBatis动态设置表名
@Select({"<script>",
  "SELECT * FROM order_${tableName} WHERE user_id = #{userId}",
  "</script>"})
List<Order> getOrdersByUserId(@Param("userId") int userId, @Param("tableName") String tableName);

四、总结

  • 分库分表是应对海量数据的重要手段
  • 合理选择分片键能显著提升系统性能
  • 实际项目中应结合业务场景灵活使用
  • 注意数据一致性、查询复杂度等问题

如果你正在做分布式系统开发,这项技能一定要掌握!🎯

希望这篇文章对你理解分库分表有所帮助。如果你还想了解如何结合分库分表实现高性能微服务架构,欢迎继续关注莫森的技术分享哦~要不要?😎