一文详解MySQL实现分库分表的详细步骤

 更新时间:2025年12月26日 14:43:05   作者:悟空码字  
在MySQL数据库的使用过程中,当数据量增长到一定规模时,单库单表的架构会面临性能瓶颈,此时就需要考虑分库分表,下面我们就来看看分库分表的具体实现方法吧

一、分库分表是什么?——数据库的“甜蜜烦恼”

把你的MySQL数据库想象成是个小单身公寓(单库单表):

  • 刚开始住进去时,东西不多,找啥都方便
  • 后来你结婚了(用户量增加),生了娃(数据量暴增),还养了条二哈(业务复杂了)
  • 现在全家挤在小公寓里,每天早上一家人抢厕所(数据库锁竞争),找双袜子要翻遍全家(全表扫描)
  • 邻居天天投诉你家太吵(性能影响其他服务)

这时候你需要: 分库:买下整栋楼!把不同的家人安排在不同楼层(业务垂直拆分) 分表:把每个房间再隔成小隔间!把袜子、内裤、外套分开放(数据水平拆分)

二、详细实施步骤——从“蜗居”到“豪宅”的装修指南

第1步:设计蓝图——想清楚再动手

-- 先看看现在的“房子”有多大
SELECT 
    TABLE_SCHEMA as '数据库',
    TABLE_NAME as '表名',
    ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) as '大小(MB)',
    TABLE_ROWS as '行数'
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = '你的数据库名'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;

-- 思考人生三连问:
-- 1. 按业务分?(用户相关、订单相关、商品相关)
-- 2. 按时间分?(2024订单、2025订单)
-- 3. 按地域分?(北京用户、上海用户)

第2步:垂直分库——让专业的人住专业的楼层

-- 原来都挤在一个库里
CREATE DATABASE single_apartment;

-- 现在买栋楼,每层一个专业户
CREATE DATABASE user_villa;      -- 用户专属楼层
CREATE DATABASE order_mansion;   -- 订单豪华层
CREATE DATABASE product_tower;   -- 商品展示层

-- 用户表搬到用户楼层
CREATE TABLE user_villa.user_info (
    user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    -- 用户相关的其他字段...
);

-- 订单表搬到订单楼层  
CREATE TABLE order_mansion.order_info (
    order_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    amount DECIMAL(10, 2),
    status TINYINT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    -- 订单相关的其他字段...
);

第3步:水平分表——每个房间都装上帝视角衣柜

方法一:按范围分表(适合时间序列)

-- 订单表按月份拆分,再也不怕找去年的订单像考古了
-- 2024年订单表
CREATE TABLE order_mansion.order_202401 (
    order_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    -- ... 其他字段
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_id (user_id),
    INDEX idx_created_at (created_at)
) PARTITION BY RANGE (MONTH(created_at)) (
    PARTITION p1 VALUES LESS THAN (2),
    PARTITION p2 VALUES LESS THAN (3),
    -- ... 更多分区
);

-- 2024年2月订单表
CREATE TABLE order_mansion.order_202402 (
    -- 结构同上
);

方法二:按哈希分表(均匀分布)

-- 用户表按ID取模分表,16张表够不够?
-- 先创建用户表模板
DELIMITER $$

CREATE PROCEDURE create_user_tables()
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < 16 DO
        SET @table_name = CONCAT('user_villa.user_info_', LPAD(i, 2, '0'));
        SET @sql = CONCAT('
            CREATE TABLE IF NOT EXISTS ', @table_name, ' (
                user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
                username VARCHAR(50) NOT NULL,
                email VARCHAR(100),
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                INDEX idx_username (username)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        ');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET i = i + 1;
    END WHILE;
END$$

DELIMITER ;

-- 执行创建
CALL create_user_tables();

第4步:路由策略——给每个数据配个“导航系统”

// Java代码示例:数据路由导航
public class ShardingNavigator {
    
    // 用户表路由:根据user_id决定去哪个表
    public static String getUserTableName(long userId) {
        int tableIndex = (int) (userId % 16);
        return String.format("user_info_%02d", tableIndex);
    }
    
    // 订单表路由:根据时间决定去哪个表
    public static String getOrderTableName(Date orderTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        return "order_" + sdf.format(orderTime);
    }
    
    // 组合查询:跨表查询就像组织家庭聚会
    public List<Order> getUserOrders(long userId, Date startTime, Date endTime) {
        List<Order> allOrders = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);
        
        // 遍历时间范围内的所有月份表
        while (calendar.getTime().before(endTime)) {
            String tableName = getOrderTableName(calendar.getTime());
            String sql = "SELECT * FROM " + tableName + " WHERE user_id = ?";
            // 执行查询并添加到结果集
            // ...
            calendar.add(Calendar.MONTH, 1);
        }
        return allOrders;
    }
}

第5步:中间件配置——请个“万能管家”

# ShardingSphere配置文件示例(YAML格式)
# 这位管家知道所有房间在哪
dataSources:
  ds0:
    url: jdbc:mysql://localhost:3306/user_villa?useSSL=false
    username: root
    password: your_password
  ds1:
    url: jdbc:mysql://localhost:3307/order_mansion?useSSL=false
    username: root
    password: your_password

shardingRule:
  tables:
    user_info:
      actualDataNodes: ds0.user_info_${0..15}
      tableStrategy:
        inline:
          shardingColumn: user_id
          algorithmExpression: user_info_${user_id % 16}
    order_info:
      actualDataNodes: ds1.order_${2024..2025}${1..12}
      tableStrategy:
        standard:
          shardingColumn: created_at
          preciseAlgorithmClassName: com.example.TimeShardingAlgorithm
  
  bindingTables:
    - user_info,order_info

第6步:数据迁移——搬家不能丢东西

-- 第一步:先抄家(备份)
CREATE TABLE order_mansion.order_202401_new LIKE order_mansion.order_202401;

-- 第二步:慢慢搬(增量迁移)
INSERT INTO order_mansion.order_202401_new
SELECT * FROM single_apartment.orders 
WHERE created_at >= '2024-01-01' 
  AND created_at < '2024-02-01';

-- 第三步:检查有没有落下的
SELECT 
    (SELECT COUNT(*) FROM single_apartment.orders 
     WHERE created_at >= '2024-01-01' AND created_at < '2024-02-01') as old_count,
    (SELECT COUNT(*) FROM order_mansion.order_202401_new) as new_count;

-- 第四步:切换门牌号(重命名)
RENAME TABLE 
    order_mansion.order_202401 TO order_mansion.order_202401_backup,
    order_mansion.order_202401_new TO order_mansion.order_202401;

第7步:全局ID生成——给每个数据发身份证

// 雪花算法:Twitter出品,必属精品
public class SnowflakeIdGenerator {
    private final long twepoch = 1288834974657L;
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    private final long sequenceBits = 12L;
    
    private long workerId;
    private long datacenterId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;
    
    public synchronized long nextId() {
        long timestamp = timeGen();
        
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时间倒流了,检查系统时间!");
        }
        
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & 4095;  // 2^12-1
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        
        lastTimestamp = timestamp;
        
        return ((timestamp - twepoch) << 22) |
               (datacenterId << 17) |
               (workerId << 12) |
               sequence;
    }
    
    // 全局唯一,趋势递增,适合分库分表
}

三、注意事项——别墅区的物业管理条例

分布式事务:楼上转账,楼下扣款,必须同时成功或失败

// 使用Seata等分布式事务解决方案
@GlobalTransactional
public void transferMoney(long fromUser, long toUser, BigDecimal amount) {
    // 1. 从用户库扣款
    // 2. 向订单库插入记录
    // 要么都成功,要么都回滚
}

跨表查询:想找张三的所有订单?得问遍所有表!

-- 分表前:一步到位
SELECT * FROM orders WHERE user_id = 123;

-- 分表后:变成侦查行动
SELECT * FROM order_202401 WHERE user_id = 123
UNION ALL
SELECT * FROM order_202402 WHERE user_id = 123
UNION ALL
-- ... 查遍所有月份表

JOIN操作:用户表和订单表在不同库?只能业务层JOIN

// 1. 先从用户库查用户
List<User> users = userDao.getUsers(condition);
List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());

// 2. 再去订单库查这些用户的订单
List<Order> orders = orderDao.getOrdersByUserIds(userIds);

// 3. 在内存中组装
Map<Long, List<Order>> userOrdersMap = groupOrdersByUser(orders);

四、总结

分库分表就像数据库的成人礼,意味着你的业务从“小打小闹”变成了“正经事业”。但是:

不要过早优化:如果你的数据还没到百万级别,别急着分表,就像不能因为将来可能变胖,现在就买XXL号裤子。

选择合适的策略:按时间分?按地域分?按业务分?这就像选择衣柜整理方式,有人喜欢按季节,有人喜欢按颜色,适合的才是最好的。

准备好工具:中间件(ShardingSphere、MyCat)是你的瑞士军刀,监控工具(Prometheus、Grafana)是你的健康检测仪。

接受不完美:分库分表后,事务复杂了,查询麻烦了,运维困难了。但这就是成长的代价,就像长大后发现世界不是非黑即白。

最后提醒:分库分表前,先试试这些“减肥方法”:

  • 加索引(给东西贴标签)
  • 优化SQL(整理收纳技巧)
  • 升级硬件(换个大房子)
  • 读写分离(男女分开用厕所)

只有当这些都不够用时,才考虑分库分表这个大工程。记住,好的架构是演进而来的,不是设计出来的。就像好的婚姻,需要慢慢磨合,不能一开始就分房睡(分库)还分床(分表)!

祝你的数据库从“小公寓”顺利升级到“豪华别墅区”,住得宽敞,查得飞快!

以上就是一文详解MySQL实现分库分表的详细步骤的详细内容,更多关于MySQL分库分表的资料请关注脚本之家其它相关文章!

相关文章

  • Ubuntu18.04安装mysql5.7.23的教程

    Ubuntu18.04安装mysql5.7.23的教程

    这篇文章主要为大家详细介绍了Ubuntu18.04安装mysql5.7.23的教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • 浅谈MySQL之select优化方案

    浅谈MySQL之select优化方案

    我们是否看到过在公司中许多查询语句都是select * xxxx,本文就主要介绍了MySQL之select优化方案,具有一定的参考价值,感兴趣的可以了解一下
    2021-08-08
  • MySQL数据库常见字段类型长度汇总大全

    MySQL数据库常见字段类型长度汇总大全

    这篇文章主要给大家介绍了关于MySQL数据库常见字段类型长度汇总大全的相关资料,需要的朋友可以参考下
    2024-05-05
  • MySQL绿色解压缩版安装与配置操作步骤

    MySQL绿色解压缩版安装与配置操作步骤

    这篇文章主要介绍了MySQL绿色解压缩版安装与配置操作步骤,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-05-05
  • mysql自增navicat_navicat如何设置主键自增

    mysql自增navicat_navicat如何设置主键自增

    通过Navicat设置MySQL表的主键自增,步骤包括:打开Navicat连接数据库,选择表并设计,右击id字段设置为主键,然后勾选自动递增功能,这样每次插入新记录时,id字段都会自动递增
    2025-01-01
  • MySQL v5.7.18 解压版本安装详细教程

    MySQL v5.7.18 解压版本安装详细教程

    这篇文章主要介绍了MySQL v5.7.18 解压版本安装详细教程,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-04-04
  • MySQL 5.7安装后默认登录密码的查看方法

    MySQL 5.7安装后默认登录密码的查看方法

    许多朋友安装MySQL 5.7之后不知道默认登录密码在哪里查看,本文小编将通过代码示例和图文结合的方式给大家介绍MySQL 5.7安装后默认登录密码的查看方法,需要的朋友可以参考下
    2023-12-12
  • MySQL日期格式以及日期函数举例详解

    MySQL日期格式以及日期函数举例详解

    这篇文章主要给大家介绍了关于MySQL日期格式及日期函数的相关资料,日期在数据库中是一个常见且重要的数据类型,在MySQL中我们可以使用各种函数和格式化选项来处理和显示日期,需要的朋友可以参考下
    2023-11-11
  • 详解如何使用DockerHub官方的MySQL镜像

    详解如何使用DockerHub官方的MySQL镜像

    MySQL是一个广泛使用的开源关系型数据库,那如何获取Mysql Docker镜像?下面通过这篇文章来一起看看如何使用DockerHub官方的MySQL镜像,有需要的朋友们可以参考借鉴。
    2016-12-12
  • 美团网技术团队分享的MySQL索引及慢查询优化教程

    美团网技术团队分享的MySQL索引及慢查询优化教程

    这篇文章主要介绍了美团网技术团队分享的MySQL索引及慢查询优化教程,结合了实际的磁盘IO情况对一些优化方案作出了分析,十分推荐!需要的朋友可以参考下
    2015-11-11

最新评论