问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

MySQL 分库分表详细介绍

创作时间:
作者:
@小白创作中心

MySQL 分库分表详细介绍

引用
CSDN
1.
https://m.blog.csdn.net/weixin_45428910/article/details/145722600

随着业务数据量的增长,单库单表的数据库架构往往难以满足性能和容量的需求。本文将详细介绍MySQL分库分表的技术方案,包括分库分表的原因、方式、策略、实现方法以及数据一致性保证等多个方面,帮助读者掌握这一重要的数据库扩展技术。

一、为什么要分库分表?

当业务数据量增长到 单库单表 难以承载的程度时,会出现:

  • 查询性能下降(索引树变大,查询变慢)。
  • 写入性能瓶颈(锁冲突严重)。
  • 存储容量受限(单表数据量超限)。
  • 数据库单点故障风险。

解决方案

分库分表(Sharding)是一种 数据库水平扩展(Scale Out)方案,将数据拆分到多个数据库或数据表中,以提升系统吞吐能力和可扩展性。

二、分库分表的两种方式

1.分表(Sharding Table):

适用于单表数据量过大(如亿级别)。
数据拆分到多个表,仍然在 同一个数据库 中。
索引变小,查询性能提升。

2.分库分表(Sharding Database + Table):

适用于单库压力过大,主从同步瓶颈。
数据拆分到多个数据库和表,解决存储和并发问题。
适合分布式架构(但事务处理变复杂)。

三、分库分表的常见策略

1. 取模(HASH 取模)

  • 方案:
  
数据库数:N  
表数:M  
分片算法:
库编号 = hash(主键) % N  
表编号 = hash(主键) % M  
  
  • 示例(假设 4 库 8 表):
    用户 ID 12345
    数据库 = 12345 % 4 = 1
    表 = 12345 % 8 = 5
    数据落入 db_1.user_5
  • 优点:
    数据分布均匀,查询性能稳定。
  • 缺点:
    扩容困难,如 N=4,扩展到 8,数据需要 重新分配(导致数据迁移复杂)。

2. 范围(RANGE 分片)

  • 方案:
  
按时间、ID 号段拆分:
用户ID 1-1,000,000 → db_1
用户ID 1,000,001-2,000,000 → db_2
  
  • 示例(按时间分表,每月一个表):
  
CREATE TABLE orders_202401 (...);
CREATE TABLE orders_202402 (...);
  
  • 优点:
    数据分布直观,易管理。
    支持按时间清理历史数据(如定期归档旧表)。
  • 缺点:
    热点数据集中(如最新数据查询压力大)。
    不同表数据量不均衡(老表访问少,新表访问多)。

3. 按业务分库(垂直拆分 Vertical Sharding)

方案:

  
不同业务拆分到不同数据库,如:
用户数据 → user_db
订单数据 → order_db
日志数据 → log_db
  
  • 优点:
    业务隔离,减少互相影响。
    单表数据量小,性能更稳定。
  • 缺点:
    跨库 JOIN 受限,需要 应用层聚合 。
    某些库压力仍然可能过大(如订单库)。

4. 一致性哈希(Consistent Hashing)

方案:

采用 一致性哈希环,动态增加/删除节点时 减少数据迁移。
常用于 分布式缓存+数据库 组合架构。

示例(4 个库,新增第 5 个库时,仅部分数据重新分配):

  • 原始:
    hash(数据) -> db_1, db_2, db_3, db_4
  • 新增 db_5:
    仅 db_4 需要迁移部分数据到 db_5
  • 优点:
    动态扩容友好,数据迁移量小。
  • 缺点:
    实现较复杂,通常结合 一致性哈希中间件(如 Redis、ES)。

四、如何实现分库分表

1. 手动分库分表(应用层控制)

示例(Java 代码实现 Hash 分库分表)

  
public class ShardingUtil {
    private static final int DB_COUNT = 4;
    private static final int TABLE_COUNT = 8;
    public static String getDatabase(String userId) {
        int dbIndex = userId.hashCode() % DB_COUNT;
        return "db_" + dbIndex;
    }
    public static String getTable(String userId) {
        int tableIndex = userId.hashCode() % TABLE_COUNT;
        return "user_" + tableIndex;
    }
    public static void main(String[] args) {
        String userId = "12345";
        System.out.println("Database: " + getDatabase(userId));
        System.out.println("Table: " + getTable(userId));
    }
}
  

2. 使用 ShardingSphere 进行自动分库分表

ShardingSphere 是 Apache 开源的数据库分库分表中间件,支持 读写分离 + 分库分表。

ShardingSphere 配置示例

  
spring:
  shardingsphere:
    datasource:
      names: db_0, db_1
      db_0:
        url: jdbc:mysql://localhost:3306/db_0
        username: root
        password: password
      db_1:
        url: jdbc:mysql://localhost:3306/db_1
        username: root
        password: password
    rules:
      sharding:
        tables:
          user:
            actual-data-nodes: db_$->{0..1}.user_$->{0..3}
            table-strategy:
              standard:
                sharding-column: id
                sharding-algorithm-name: user-inline
        sharding-algorithms:
          user-inline:
            type: INLINE
            props:
              algorithm-expression: user_$->{id % 4}
  

五、如何保证分库分表的数据一致性

1. 事务管理

  • 分库后本地事务(Single DB Transaction) 仍然有效。
  • 跨库事务(Distributed Transaction) 需要使用 XA 事务 或 TCC 事务补偿机制。

2. 分布式 ID

  • 由于 AUTO_INCREMENT 无法跨库,需要使用 分布式 ID 生成器:
  • UUID(唯一但查询效率低)
  • 雪花算法(Snowflake)
  • MySQL 自增 ID 方案(每库步长不同)
  • Redis 生成唯一 ID

六、总结

选型建议

数据量 < 5000万:单库,索引优化+分区表。
5000万 ~ 5亿:单库分表(Hash 分表)。

5亿以上:分库分表+分布式架构。

这样可以 保证数据库可扩展性、查询性能、事务一致性。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号