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

MySQL 分库分表详解(含实践示例)

十分想念顺店杂可。。。

分库分表是应对 MySQL 单库单表瓶颈的核心手段,通过拆分数据分散存储和访问压力。本文从拆分维度、实现方式、实践示例到关键挑战进行全面梳理,帮助理解和落地分库分表方案。

一、按拆分维度分类

1. 垂直分表(Column Sharding)

定义

将单表中字段按访问频率和关联性拆分到多个表,各表共享同一主键,业务上属于同一主体。

适用场景
  • 单表字段过多(如超过 50 个),查询时加载冗余字段导致 IO 效率低;
  • 存在大字段(textblob)或低频访问字段,拖慢核心查询;
  • 字段访问频率差异显著(如用户核心信息 vs 扩展资料)。
优缺点
优点缺点
减少单表字段数,降低 IO 成本需维护多表关联,增加 join 操作
核心字段与大字段分离,提升查询效率跨表查询增加业务复杂度
表结构更贴合业务模块-
实践示例
-- 原用户表(字段冗余)
CREATE TABLE `user` (`id` bigint PRIMARY KEY AUTO_INCREMENT,`username` varchar(50) NOT NULL,  -- 高频`password` varchar(100) NOT NULL,  -- 高频`age` int,  -- 高频`address` text,  -- 低频+大字段`intro` text,  -- 低频+大字段`create_time` datetime NOT NULL
);-- 拆分后:核心信息表(高频访问)
CREATE TABLE `user_core` (`id` bigint PRIMARY KEY AUTO_INCREMENT,`username` varchar(50) NOT NULL,`password` varchar(100) NOT NULL,`age` int,`create_time` datetime NOT NULL
);-- 拆分后:扩展信息表(低频访问)
CREATE TABLE `user_ext` (`user_id` bigint PRIMARY KEY,  -- 与user_core.id关联`address` text,`intro` text,FOREIGN KEY (`user_id`) REFERENCES `user_core`(`id`) ON DELETE CASCADE
);-- 插入数据(需同时写入两表)
INSERT INTO `user_core` (username, password, age, create_time)
VALUES ('zhangsan', 'hash_pwd', 25, '2023-01-01 08:00:00');INSERT INTO `user_ext` (user_id, address, intro)
VALUES (LAST_INSERT_ID(), 'Beijing', 'A developer');-- 查询用户完整信息(join两表)
SELECT c.*, e.address, e.intro 
FROM `user_core` c
LEFT JOIN `user_ext` e ON c.id = e.user_id
WHERE c.username = 'zhangsan';

2. 垂直分库(Database Sharding by Business)

定义

不同业务模块的数据库拆分到独立实例,各库无直接关联,按业务边界隔离。

适用场景
  • 单库承载多业务,出现 CPU、内存或 IO 瓶颈;
  • 业务模块访问频率差异大(如订单库并发远高于商品库);
  • 业务耦合度低,可独立扩展(如用户、订单、商品模块)。
优缺点
优点缺点
分散单库压力,各库可独立配置资源跨库业务需处理分布式事务
业务隔离,某库故障不影响其他模块全局表(如字典表)需冗余维护
便于按业务分工维护跨库 join 困难
实践示例
-- 原单库架构:all_in_one_db(包含用户、订单、商品表)
all_in_one_db
├─ user(用户表)
├─ order(订单表)
└─ product(商品表)-- 垂直分库后:按业务拆分3个独立库
user_db(用户库)
└─ user(用户相关表)order_db(订单库)
└─ order(订单相关表)product_db(商品库)
└─ product(商品相关表)

-- 分库后,查询用户订单需跨库操作(伪代码示意)
-- 1. 从 user_db 查用户信息
SELECT * FROM user_db.user WHERE id = 1001;

-- 2. 从 order_db 查订单信息
SELECT * FROM order_db.order WHERE user_id = 1001;

3. 水平分表(Row Sharding)

定义

将单表中数据按规则拆分到多个结构相同的表,各表字段一致,数据不同(按行拆分)。

拆分规则
规则类型说明适用场景示例
范围拆分按数值 / 时间范围拆分时间序列数据(日志、订单)订单表按月份分表:order_202301、order_202302
哈希拆分按关键字哈希取模数据访问均匀(用户表)用户表按 user_id%4 分 4 表:user_0~user_3
列表拆分按枚举值拆分数据有明确分类(地区、状态)订单表按地区分表:order_beijing、order_shanghai
复合拆分结合多种规则复杂场景(大促订单)先按时间范围,再按用户 ID 哈希
适用场景
  • 单表数据量过大(超 1000 万行),查询 / 索引维护效率低;
  • 单表写入压力高(每秒数千条 insert),磁盘 IO 瓶颈明显。
优缺点
优点缺点
降低单表数据量,提升读写效率跨表查询需聚合结果(复杂)
可按需扩展表数量分表规则变更需迁移全量数据
各分表可独立优化(索引、存储)需维护路由逻辑
实践示例
示例 1:按时间范围分表(订单表)
-- 2023年1月订单表
CREATE TABLE `order_202301` (`id` bigint PRIMARY KEY AUTO_INCREMENT,`order_no` varchar(32) UNIQUE NOT NULL,`user_id` bigint NOT NULL,`amount` decimal(10,2) NOT NULL,`create_time` datetime NOT NULL,INDEX idx_user_id (`user_id`)
);-- 2023年2月订单表(结构与order_202301一致)
CREATE TABLE `order_202302` (...);-- 插入数据(按create_time路由到对应表)
INSERT INTO `order_202301` (order_no, user_id, amount, create_time)
VALUES ('ORD20230105001', 1001, 99.99, '2023-01-05 10:30:00');
示例 2:按哈希拆分(用户表)
-- 按user_id%4分4张表(user_0~user_3)
CREATE TABLE `user_0` (`id` bigint PRIMARY KEY AUTO_INCREMENT,`user_id` bigint UNIQUE NOT NULL,  -- 哈希分表键`username` varchar(50) NOT NULL,`create_time` datetime NOT NULL
);CREATE TABLE `user_1` (...);  -- 结构与user_0一致
CREATE TABLE `user_2` (...);
CREATE TABLE `user_3` (...);-- 插入数据(按user_id哈希路由)
-- user_id=1001:1001%4=1 → 插入user_1
INSERT INTO `user_1` (user_id, username, create_time)
VALUES (1001, 'zhangsan', '2023-01-01 08:00:00');

4. 水平分库(Database Sharding by Data)

定义

水平分表后的表分布到多个数据库实例,同时分散库和表的压力(分库 + 分表结合)。

适用场景
  • 水平分表后单库压力仍过大(CPU / 内存 / 连接数瓶颈);
  • 需支持更高并发(多库可同时处理更多请求)。
优缺点
优点缺点
同时分散库和表的压力,支持高并发架构复杂,需管理多库多表路由
可按库隔离资源(热点库单独配置)跨库事务和 join 难度大
实践示例
-- 分4个库,每个库含4张订单表(共4库×4表=16分片)
order_db_0(库0)
├─ order_0(user_id%16=0)
├─ order_1(user_id%16=1)
├─ order_2(user_id%16=2)
└─ order_3(user_id%16=3)order_db_1(库1)
├─ order_4(user_id%16=4)
├─ order_5(user_id%16=5)
├─ order_6(user_id%16=6)
└─ order_7(user_id%16=7)order_db_2(库2)→ 存储8-11分片
order_db_3(库3)→ 存储12-15分片-- 路由规则:
-- 库索引 = user_id % 4 
-- 表索引 = user_id % 16 
-- 例:user_id=1001 → 1001%4=1(库1),1001%16=9(表9)
INSERT INTO `order_db_1.order_9` (order_no, user_id, amount)
VALUES ('ORD20230501001', 1001, 199.99);

二、按实现方式分类

1. 客户端方案(嵌入式分片)

原理

在应用中集成分片逻辑(如 JDBC 驱动扩展),直接路由请求到目标库表。

代表工具

Sharding-JDBC(Apache ShardingSphere)

实现流程
  1. 应用配置分片规则(分库键、分表键、路由算法);
  2. Sharding-JDBC 拦截 SQL,解析后路由到目标库表;
  3. 聚合结果返回给应用。
优缺点
优点缺点
无中间件,性能损耗低(仅 SQL 解析)与应用耦合,需在应用层维护规则
架构简单(应用与数据库直连)多语言支持差(主要支持 Java)
-扩容需重启应用更新配置
示例配置(Sharding-JDBC)
# 分片规则配置(简化版)
spring:shardingsphere:rules:sharding:tables:t_order:  # 逻辑表名actual-data-nodes: order_db_${0..3}.order_${0..15}  # 实际分片database-strategy:  # 分库策略standard:sharding-column: user_idsharding-algorithm-name: order_db_inlinetable-strategy:  # 分表策略standard:sharding-column: user_idsharding-algorithm-name: order_table_inlinesharding-algorithms:order_db_inline:  # 分库算法(user_id%4)type: INLINEprops:algorithm-expression: order_db_${user_id % 4}order_table_inline:  # 分表算法(user_id%16)type: INLINEprops:algorithm-expression: order_${user_id % 16}

2. 中间件方案(代理层分片)

原理

在应用与数据库间部署代理服务,统一处理路由、聚合、事务等逻辑。

代表工具

MyCat、ShardingSphere-Proxy、ProxySQL

实现流程
  1. 应用连接代理(如 MyCat),按单库单表方式写 SQL;
  2. 中间件解析 SQL,按规则路由到目标库表;
  3. 聚合结果返回给应用。
优缺点
优点缺点
与应用解耦,支持多语言(标准 MySQL 协议)中间件可能成为性能瓶颈(需集群部署)
集中管理分片规则,扩容无需改应用额外网络开销(应用→中间件→数据库)
可扩展读写分离、容灾等功能-
示例(MyCat 逻辑表配置)
<!-- MyCat schema.xml配置 -->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"><!-- 逻辑表t_order,对应物理分片 --><table name="t_order" dataNode="dn$0-3" rule="order_sharding" />
</schema><!-- 数据节点(分库) -->
<dataNode name="dn0" dataHost="host1" database="order_db_0" />
<dataNode name="dn1" dataHost="host1" database="order_db_1" />
<dataNode name="dn2" dataHost="host2" database="order_db_2" />
<dataNode name="dn3" dataHost="host2" database="order_db_3" /><!-- 分片规则(user_id哈希) -->
<rule name="order_sharding"><ruleAlgorithm name="mod-long"><properties><property name="column">user_id</property><property name="count">4</property>  <!-- 分4库 --></properties></ruleAlgorithm>
</rule>

3. 数据库原生方案(分区表)

原理

MySQL 原生支持分区表,物理上拆分到多个文件,逻辑上为单表,数据库自动管理路由。

分区类型
  • 范围分区(RANGE):按范围拆分(如时间、数值);
  • 列表分区(LIST):按枚举值拆分(如地区);
  • 哈希分区(HASH):按哈希值拆分;
  • 键分区(KEY):基于 MySQL 内部哈希函数。
优缺点
优点缺点
对应用透明,无需修改代码仍属单库,无法分散实例压力(CPU / 内存瓶颈)
维护简单(MySQL 自动管理)分区数有限制(过多影响性能)
支持分区级操作(如删除历史分区)不支持跨分区全局索引
实践示例(RANGE 分区)
-- 订单表按季度分区
CREATE TABLE `order_partition` (`id` bigint PRIMARY KEY AUTO_INCREMENT,`order_no` varchar(32) UNIQUE NOT NULL,`user_id` bigint NOT NULL,`amount` decimal(10,2) NOT NULL,`create_time` datetime NOT NULL,INDEX idx_user_id (`user_id`)
) 
PARTITION BY RANGE (TO_DAYS(create_time)) (PARTITION p2023Q1 VALUES LESS THAN (TO_DAYS('2023-04-01')),PARTITION p2023Q2 VALUES LESS THAN (TO_DAYS('2023-07-01')),PARTITION p2023Q3 VALUES LESS THAN (TO_DAYS('2023-10-01')),PARTITION p2023Q4 VALUES LESS THAN (TO_DAYS('2024-01-01'))
);-- 插入数据(自动路由到对应分区)
INSERT INTO `order_partition` (order_no, user_id, amount, create_time)
VALUES ('ORD20230501001', 1001, 199.99, '2023-05-01 14:30:00');  -- 进入p2023Q2-- 查询指定分区(优化性能)
SELECT * FROM `order_partition` PARTITION (p2023Q2) 
WHERE user_id = 1001;

三、关键挑战与解决方案

挑战解决方案
跨库 join1. 数据冗余(如订单表冗余商品名称);2. 应用层组装(先查 A 库,再查 B 库,内存 join);3. 中间件支持(MyCat 全局表、ER 表)
分布式事务1. 最终一致性(消息队列 + 本地事务);2. 2PC 协议(Seata);3. TCC 补偿机制
全局 ID1. 雪花算法(Snowflake);2. 数据库自增 ID 分段(ShardingSphere 分布式 ID);3. Redis 自增
扩容迁移1. 双写迁移(旧库和新库同时写入,校验一致后切换);2. 中间件弹性伸缩(ShardingSphere)

四、总结

分库分表需结合业务场景选择方案:

  • 字段多、访问频率差异大 → 垂直分表;
  • 业务模块独立、单库压力大 → 垂直分库;
  • 单表数据量过大(千万级 +) → 水平分表;
  • 分表后单库仍压力大 → 水平分库;
  • 轻量场景、不愿引入中间件 → MySQL 分区表;
  • 高并发、多语言 → 中间件方案(MyCat/ShardingSphere-Proxy);
  • 性能敏感、Java 应用 → 客户端方案(Sharding-JDBC)。

实际落地中,通常采用 “垂直分库 + 水平分表” 组合,并提前规划分片规则(预留扩容空间),结合中间件降低维护复杂度。

http://www.dtcms.com/a/329680.html

相关文章:

  • C++ 中构造函数参数对父对象的影响:父子控件管理机制解析
  • 当img占不满div时,图片居中显示,两侧加当前图片模糊效果
  • Redis基础命令
  • 【易错题】C语言
  • Git Bash
  • Linux内存管理机制分析
  • 汽车免拆诊断案例 | 2010款奥迪A4L车行驶中发动机偶尔自动熄火
  • uniapp微信小程序-登录页面验证码的实现(springboot+vue前后端分离)EasyCaptcha验证码 超详细
  • 超实用!ToDesk/网易UU/向日葵:远程办公文件协作效率与安全实测
  • redis 内存使用率高居高不下,如何分析 key占用情况
  • 物联网之小白调试网关设备
  • 18.9 BERT问答模型实战:从数据到部署的完整指南
  • C++面试艺术:我的思考与避坑指南
  • framebuffer
  • 深入理解Java Set集合特性
  • windows下以all-in-one模式快速启动jaeger
  • Linux学习-UI技术
  • ROS2实用工具
  • Spring AI 的特性 及其 最佳实践
  • CompletableFuture介绍及使用方式
  • 天猫商品评论API:获取商品热门评价与最新评价
  • Jmeter TPS与QPS
  • Ant Design 的 `Image` 组件,通过 `preview.src` 加载本地图片文件
  • Dockerhub 代理设置
  • 破解测试数据困境:5招兼顾安全与真实性
  • Nature Communications 西湖大学姜汉卿教授:弹电磁驱动新范式--赋能昆虫级软体机器人的肌肉仿生策略
  • HTML第三次作业
  • Redis ubuntu下载Redis的C++客户端
  • Ubuntu 20.04 虚拟机安装完整教程:从 VMware 到 VMware Tools
  • 如何在 Ubuntu 24.04 LTS Noble Linux 上安装 FileZilla Server