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)等方式。

相关推荐
程序员云帆哥12 分钟前
MySQL JDBC Driver URL参数配置规范
数据库·mysql·jdbc
TDengine (老段)30 分钟前
TDengine 数学函数 FLOOR 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
大气层煮月亮1 小时前
Oracle EBS ERP开发——报表生成Excel标准模板设计
数据库·oracle·excel
云和数据.ChenGuang1 小时前
达梦数据库的命名空间
数据库·oracle
三三木木七2 小时前
mysql拒绝连接
数据库·mysql
蹦跶的小羊羔2 小时前
sql数据库语法
数据库·sql
唐古乌梁海2 小时前
【mysql】InnoDB的聚簇索引和非聚簇索引工作原理
数据库·mysql
我变秃了也没变强2 小时前
pgsql配置密码复杂度策略
数据库·postgresql
PawSQL2 小时前
企业级SQL审核工具PawSQL介绍(1) - 六大核心能力
数据库·sql·oracle
幼稚园的山代王2 小时前
NoSQL介绍
数据库·nosql