当前位置: 首页 > article >正文

MySQL 分库分表实战(一)

在面对大规模数据和高并发访问时,单个数据库或单表可能会成为系统瓶颈,影响系统的性能和可扩展性。分库分表是解决海量数据存储和访问性能问题的常用技术手段,通过将数据拆分到多个库或表中,实现读写分离、负载均衡和水平扩展。


一、分库分表的核心概念

1. 什么是分库分表?
  • 分库:将数据水平拆分到多个数据库实例中,每个库存储一部分数据。
  • 分表:在同一个数据库中,将大表拆分为多个小表,每个小表存储部分数据。
2. 为什么需要分库分表?
  • 性能瓶颈:单表数据量过大,导致查询缓慢。
  • 存储瓶颈:单个数据库实例存储能力有限。
  • 高并发需求:单个数据库无法承受大量并发请求。
  • 数据库主从架构不足:主从复制仅解决了读性能问题,写入仍存在瓶颈。

二、分库分表策略

1. 分库策略
  • 按业务模块分库:不同业务模块独立数据库。例如:订单库、用户库。
  • 水平分库:相同业务数据按照一定规则(如 user_id 取模)分布在多个数据库中。
2. 分表策略
  • 范围分表:按时间、ID 范围分表。例如:订单表按月份拆分。
  • 哈希分表:通过哈希函数将数据均匀分布到多个表中。
  • 按字段分表:根据业务关键字段(如 user_id)取模分表。

三、实战:订单系统分库分表设计

1. 需求分析
  • 每天新增订单百万级,订单表增长速度快,单表逐渐达到亿级数据。
  • 查询订单主要通过 user_idorder_id 进行。
  • 目标:将订单表拆分,减少单表数据量,提升查询性能。

2. 数据库设计

订单主表(order_main)结构

字段名类型描述
order_idBIGINT订单号(全局唯一)
user_idBIGINT用户ID
amountDECIMAL(10,2)订单金额
statusVARCHAR(20)订单状态
create_timeTIMESTAMP下单时间

四、分库分表方案

1. 分表策略:按用户ID分表
  • 将订单数据按照用户ID分散存储到多个表中,减少单表数据量。
  • 例如:
    • order_0 存储 user_id % 4 = 0 的数据
    • order_1 存储 user_id % 4 = 1 的数据
    • 以此类推…

2. 创建分表 SQL
-- 创建4个分表
CREATE TABLE order_0 (
    order_id BIGINT PRIMARY KEY,
    user_id BIGINT,
    amount DECIMAL(10, 2),
    status VARCHAR(20),
    create_time TIMESTAMP
);

CREATE TABLE order_1 LIKE order_0;
CREATE TABLE order_2 LIKE order_0;
CREATE TABLE order_3 LIKE order_0;

3. 编写分表插入逻辑
-- 插入订单数据
DELIMITER //
CREATE PROCEDURE insert_order(
    IN p_order_id BIGINT,
    IN p_user_id BIGINT,
    IN p_amount DECIMAL(10,2),
    IN p_status VARCHAR(20)
)
BEGIN
    SET @table_name = CONCAT('order_', p_user_id % 4);
    SET @sql = CONCAT(
        'INSERT INTO ', @table_name, 
        ' (order_id, user_id, amount, status, create_time) ',
        'VALUES (?, ?, ?, ?, NOW())'
    );
    PREPARE stmt FROM @sql;
    EXECUTE stmt USING p_order_id, p_user_id, p_amount, p_status;
    DEALLOCATE PREPARE stmt;
END //
DELIMITER ;

五、查询分表数据

-- 查询订单(user_id = 101 的订单记录)
DELIMITER //
CREATE PROCEDURE select_order(IN p_user_id BIGINT)
BEGIN
    SET @table_name = CONCAT('order_', p_user_id % 4);
    SET @sql = CONCAT('SELECT * FROM ', @table_name, ' WHERE user_id = ?');
    PREPARE stmt FROM @sql;
    EXECUTE stmt USING p_user_id;
    DEALLOCATE PREPARE stmt;
END //
DELIMITER ;

六、分库分表的路由逻辑实现

在应用层或中间件中,需要实现分库分表路由逻辑。以下是简单的 Java 示例:

public class OrderRouter {
    private static final int DB_COUNT = 2;
    private static final int TABLE_COUNT = 4;

    // 根据 user_id 选择数据库
    public String getDatabase(long userId) {
        int dbIndex = (int) (userId % DB_COUNT);
        return "db_order_" + dbIndex;
    }

    // 根据 user_id 选择表
    public String getTable(long userId) {
        int tableIndex = (int) (userId % TABLE_COUNT);
        return "order_" + tableIndex;
    }
}

七、批量删除旧订单

需求:删除 1 年前的历史订单数据,避免长事务阻塞。

-- 分批删除旧订单
DELIMITER //
CREATE PROCEDURE batch_delete_orders(IN days_ago INT)
BEGIN
    DECLARE rows_affected INT DEFAULT 1;

    REPEAT
        DELETE FROM order_0 WHERE create_time < NOW() - INTERVAL days_ago DAY LIMIT 1000;
        SET rows_affected = ROW_COUNT();
    UNTIL rows_affected = 0 END REPEAT;

    REPEAT
        DELETE FROM order_1 WHERE create_time < NOW() - INTERVAL days_ago DAY LIMIT 1000;
        SET rows_affected = ROW_COUNT();
    UNTIL rows_affected = 0 END REPEAT;
END //
DELIMITER ;

八、分库分表后的数据汇总与查询

问题:分库分表后无法直接执行跨表或跨库查询。
解决方法

  1. 中间件:使用 Sharding-JDBC、MyCat 等数据库中间件,自动路由和聚合查询。
  2. 数据汇总表:定期将分表数据汇总到一个大表,便于查询分析。
  3. 应用层合并:在应用层进行多表查询,将结果合并处理。

九、分库分表带来的问题与解决方案

问题解决方案
跨库事务使用分布式事务(如 Seata)或最终一致性方案
ID 唯一性使用雪花算法或分布式 ID 生成器
跨表分页先分库分表查询,再在应用层进行分页处理
数据迁移复杂逐步迁移,灰度测试,减少业务影响

十、总结

  1. 分库分表是一种解决数据库扩展性问题的有效方案,但需要权衡复杂性和开发成本。
  2. 分表策略需结合业务特性选择,常用的包括哈希分表、范围分表和按时间分表。
  3. 通过存储过程或应用层实现分表路由,提高分库分表操作的灵活性和可维护性。
  4. 定期清理历史数据,减少存储压力,避免表数据量过大导致性能下降。

分库分表是数据库架构设计中不可或缺的重要技术,合理设计能显著提升系统的稳定性和可扩展性。


http://www.kler.cn/a/472898.html

相关文章:

  • MySQL insert or update方式性能比较
  • vscode通过ssh连接服务器实现免密登录
  • 【第01阶段-基础必备篇-第二部分--Python之基础】04 函数
  • 路由器的转发表
  • STM32U575按键转换及设备驱动
  • 【GOOD】A Survey of Deep Graph Learning under Distribution Shifts
  • 无网络时自动切换备用网络环境
  • C++二十三种设计模式之迭代器模式
  • Python爬虫基础——XPath表达式
  • ffmpeg之h264格式转yuv
  • WEBRTC前端播放 播放器组件封装
  • 【Linux】深入理解文件系统(超详细)
  • 自动化执行 SQL 脚本解决方案
  • 十六、Vue 组件
  • 《深入浅出HTTPS​​​​​​​​​​​​​​​​​》读书笔记(26):数字签名
  • 【数据结构-堆】【二分】力扣3296. 移山所需的最少秒数
  • 牛客网刷题 ——C语言初阶(5操作符)——BC90 矩阵计算
  • 解决word桌面图标空白
  • UTTracker背景矫正模块详解:解决无人机追踪中的摄像头运动问题
  • Ruby语言的正则表达式
  • WebSocket 设计思路
  • 怎样用云手机进行海外社媒矩阵引流?
  • 【Linux】lnav - 适用于Linux和Unix的出色终端日志文件查看器
  • windows从0开始配置llamafactory微调chatglm3-6b
  • 使用vue-pdf预览pdf和解决pdf电子签章显示问题
  • 【中标喜讯分享】泰迪智能科技实力中标长春医学高等专科学校健康大数据管理与服务专业实训软件采购项目