MySQL 分库分表

对于使用 MySQL 作为数据库管理系统的应用来说,当数据量达到一定规模时,单库单表的架构会面临性能瓶颈,如查询缓慢、写入性能下降等问题。为了解决这些问题,可以使用分库分表技术。

二、为什么需要分库分表

2.1 单库单表的局限性

数据量过大:随着业务的发展,单表的数据量可能会达到数十亿甚至更多,这会导致索引变得庞大,查询时的磁盘 I/O 开销增加,从而影响查询性能。

并发压力:大量的并发读写请求会使数据库服务器的 CPU、内存和磁盘 I/O 资源达到瓶颈,导致响应时间变长,甚至出现数据库崩溃的情况。

2.2 分库分表的好处

提升性能:通过将数据分散到多个数据库和表中,可以减少单个数据库和表的数据量,从而提高查询和写入的性能。

增强扩展性:分库分表可以方便地增加数据库服务器和表的数量,以应对不断增长的数据量和并发请求。

三、分库分表的原理

3.1 分库

分库是将一个数据库中的数据分散到多个数据库中。可以按照业务功能、数据类型等进行划分。例如,将用户相关的数据存放在一个数据库中,将订单相关的数据存放在另一个数据库中。

3.2 分表

分表是将一个表中的数据分散到多个表中。常见的分表方式有水平分表和垂直分表。

水平分表:将表按照行进行划分,将不同行的数据存储到不同的表中。例如,按照用户 ID 的哈希值将用户数据分散到多个表中。

垂直分表:将表按照列进行划分,将不同列的数据存储到不同的表中。例如,将一个包含用户基本信息和详细信息的表拆分成两个表,一个存储基本信息,另一个存储详细信息。

四、常见的分库分表实现方式

4.1 客户端分片

客户端分片是指在应用程序端实现分库分表的逻辑。应用程序根据规则将数据路由到不同的数据库和表中。

实现思路

  1. 数据路由规则设计:确定如何将数据映射到不同的数据库和表,常见的规则有哈希取模、范围划分等。

  2. 数据库连接管理:使用数据库连接池来管理与各个数据库的连接,提高连接的复用性和性能。

  3. SQL 语句生成:根据数据路由结果,生成对应的 SQL 语句,将数据插入到正确的数据库和表中。

    #include <iostream>
    #include <string>
    #include <vector>
    #include <mysql_driver.h>
    #include <mysql_connection.h>
    #include <cppconn/statement.h>
    #include <cppconn/prepared_statement.h>
    #include <cppconn/resultset.h>
    #include <cppconn/exception.h>
    #include <functional>

    // 哈希函数
    int hashFunction(int key, int numShards) {
    return std::hash<int>()(key) % numShards;
    }

    // 数据库连接信息
    struct DatabaseInfo {
    std::string host;
    std::string user;
    std::string password;
    std::string database;
    };

    // 分库分表管理器
    class ShardingManager {
    public:
    ShardingManager(const std::vector<DatabaseInfo>& dbs, int numTablesPerDb)
    : databases(dbs), numTablesPerDb(numTablesPerDb) {
    driver = get_mysql_driver_instance();
    }

    复制代码
     // 插入数据
     void insertData(int id, const std::string& name) {
         int dbIndex = hashFunction(id, databases.size());
         int tableIndex = hashFunction(id, numTablesPerDb);
         std::string tableName = "table_" + std::to_string(tableIndex);
    
         try {
             sql::Connection* con = driver->connect(databases[dbIndex].host, databases[dbIndex].user, databases[dbIndex].password);
             con->setSchema(databases[dbIndex].database);
    
             std::string sql = "INSERT INTO " + tableName + " (id, name) VALUES (?, ?)";
             sql::PreparedStatement* pstmt = con->prepareStatement(sql);
             pstmt->setInt(1, id);
             pstmt->setString(2, name);
             pstmt->execute();
    
             delete pstmt;
             delete con;
         } catch (sql::SQLException& e) {
             std::cerr << "SQLException: " << e.what() << std::endl;
         }
     }

    private:
    std::vector<DatabaseInfo> databases;
    int numTablesPerDb;
    sql::mysql::MySQL_Driver* driver;
    };

    int main() {
    // 数据库连接信息
    std::vector<DatabaseInfo> dbs = {
    {"localhost", "user1", "password1", "db1"},
    {"localhost", "user2", "password2", "db2"}
    };

    复制代码
     // 每个数据库中的表数量
     int numTablesPerDb = 2;
    
     // 创建分库分表管理器
     ShardingManager shardingManager(dbs, numTablesPerDb);
    
     // 插入数据
     shardingManager.insertData(1, "John");
     shardingManager.insertData(2, "Jane");
    
     return 0;

    }

4.2 中间件分片

中间件分片是指在应用程序和数据库之间引入一个中间件,由中间件来实现分库分表的逻辑。常见的 MySQL 分库分表中间件有 MyCAT、ShardingSphere 等。

MyCAT 示例

MyCAT 是一个开源的 MySQL 中间件,它可以将多个 MySQL 数据库和表进行逻辑上的整合,为应用程序提供统一的访问接口。

五、分库分表的应用场景

5.1 电商系统

在电商系统中,订单数据和用户数据量非常大。可以将订单数据按照订单创建时间进行水平分表,将用户数据按照用户 ID 进行水平分表。同时,可以将订单数据和用户数据分别存储在不同的数据库中,以提高性能和扩展性。

5.2 社交系统

在社交系统中,用户的动态数据和好友关系数据量也很大。可以将用户动态数据按照用户 ID 进行水平分表,将好友关系数据按照用户 ID 进行垂直分表。

六、分库分表的注意事项

6.1 事务处理

分库分表后,跨数据库和表的事务处理变得更加复杂。可以使用分布式事务解决方案,如两阶段提交、TCC(Try-Confirm-Cancel)等。

6.2 数据迁移

在进行分库分表时,需要将原有的数据迁移到新的数据库和表中。数据迁移过程中需要注意数据的一致性和完整性。

6.3 全局唯一 ID

分库分表后,需要确保生成的 ID 在所有数据库和表中是唯一的。可以使用 UUID、数据库自增 ID、分布式 ID 生成器(如 Snowflake)等方式。

相关推荐
半桶水专家1 小时前
使用frpc链接内网的mysql
数据库·mysql·adb
264玫瑰资源库1 小时前
网狐旗舰大联盟组件源码私测笔记:结构分层、UI重构与本地实操全流程
java·前端·数据库·笔记·ui·重构
KaiwuDB3 小时前
KaiwuDB X 遨博智能 | 构建智能产线监测管理新系统
大数据·数据库·kaiwudb·分布式多模数据库
程序猿不脱发23 小时前
mysql中int(1) 和 int(10) 有什么区别?
数据库·mysql
Themberfue3 小时前
Redis ⑨-Jedis | Spring Redis
java·数据库·redis·sql·spring·缓存
囚~徒~3 小时前
shell_plus
数据库·sqlite
越来越无动于衷3 小时前
sql错题(1)
数据库·sql
筏.k4 小时前
Redis 数据类型详解(一):String 类型全解析
数据库·redis·缓存
一只栖枝5 小时前
Oracle OCP证书有效期是三年?
数据库·oracle·开闭原则·ocp证书·考试流程