外观
MySQL 垂直拆分与水平拆分
垂直拆分
基本概念
垂直拆分是指将一个表按照列的方式拆分成多个表,每个表包含原表的一部分列。垂直拆分也可以指将一个数据库按照功能模块拆分成多个数据库。
拆分方式
垂直分表
功能:将一个表按照列的相关性拆分成多个表
拆分原则:
- 将经常一起查询的列放在同一个表中
- 将不经常使用的列拆分到单独的表中
- 将大字段(如TEXT、BLOB)拆分到单独的表中
- 按照业务逻辑将列分组
使用示例:
原表结构:
sql
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
password VARCHAR(255),
bio TEXT,
avatar BLOB,
created_at DATETIME
);拆分后:
sql
-- 核心信息表
CREATE TABLE users_core (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
password VARCHAR(255),
created_at DATETIME
);
-- 扩展信息表
CREATE TABLE users_extra (
user_id INT PRIMARY KEY,
bio TEXT,
avatar BLOB,
FOREIGN KEY (user_id) REFERENCES users_core(id)
);垂直分库
功能:将一个数据库按照功能模块拆分成多个数据库
拆分原则:
- 按照业务模块拆分
- 将相关性高的表放在同一个数据库中
- 考虑跨库 join 的影响
- 考虑事务处理的复杂性
使用示例:
- 用户数据库:包含用户相关表
- 订单数据库:包含订单相关表
- 产品数据库:包含产品相关表
- 日志数据库:包含日志相关表
优点
- 降低表的复杂度,提高查询性能
- 减少I/O操作,提高数据访问效率
- 便于维护和管理
- 支持不同业务模块的独立扩展
- 提高数据安全性,不同模块数据隔离
缺点
- 增加了系统复杂度
- 可能需要跨表 join,影响查询性能
- 事务处理变得复杂
- 数据一致性维护难度增加
适用场景
- 表中包含大字段,影响查询性能
- 表中列的访问频率差异较大
- 不同业务模块之间的耦合度较低
- 系统需要独立扩展不同业务模块
水平拆分
基本概念
水平拆分是指将一个表按照行的方式拆分成多个表,每个表包含原表的一部分行。水平拆分也可以指将一个数据库拆分成多个数据库实例。
拆分方式
水平分表
功能:将一个表按照行的方式拆分成多个表,所有表的结构相同
拆分原则:
- 选择合适的分片键
- 确保数据均匀分布
- 考虑查询模式
- 考虑扩容的便利性
分片键选择:
- 频繁用于查询条件的列
- 具有高基数的列
- 分布均匀的列
- 便于范围查询的列
使用示例:
按用户ID取模拆分:
sql
-- 用户表1:user_id % 4 = 0
CREATE TABLE users_0 (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
created_at DATETIME
);
-- 用户表2:user_id % 4 = 1
CREATE TABLE users_1 (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
created_at DATETIME
);
-- 用户表3:user_id % 4 = 2
CREATE TABLE users_2 (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
created_at DATETIME
);
-- 用户表4:user_id % 4 = 3
CREATE TABLE users_3 (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
created_at DATETIME
);水平分库
功能:将一个数据库拆分成多个数据库实例,每个实例包含一部分数据
拆分原则:
- 与水平分表类似,但拆分粒度更大
- 考虑数据库实例的负载均衡
- 考虑跨库查询的复杂性
- 考虑数据备份和恢复的便利性
使用示例:
- 数据库实例1:存储user_id % 4 = 0的数据
- 数据库实例2:存储user_id % 4 = 1的数据
- 数据库实例3:存储user_id % 4 = 2的数据
- 数据库实例4:存储user_id % 4 = 3的数据
分片策略
范围分片
功能:按照分片键的范围将数据分配到不同的分片
优点:
- 便于范围查询
- 便于扩容
- 数据分布可控
缺点:
- 可能导致数据分布不均匀
- 热点数据可能集中在某个分片
适用场景:
- 分片键是连续的(如时间、ID)
- 范围查询频繁
使用示例:
分片1:id < 1000000
分片2:1000000 <= id < 2000000
分片3:2000000 <= id < 3000000哈希分片
功能:通过哈希函数将分片键转换为哈希值,根据哈希值分配到不同的分片
优点:
- 数据分布均匀
- 避免热点数据
缺点:
- 范围查询性能较差
- 扩容复杂
适用场景:
- 分片键分布均匀
- 精确查询频繁
- 无明显热点数据
使用示例:
分片1:hash(user_id) % 4 = 0
分片2:hash(user_id) % 4 = 1
分片3:hash(user_id) % 4 = 2
分片4:hash(user_id) % 4 = 3列表分片
功能:按照分片键的具体值列表将数据分配到不同的分片
优点:
- 数据分布可控
- 便于业务逻辑关联
缺点:
- 可能导致数据分布不均匀
- 扩容需要修改分片规则
适用场景:
- 分片键的值较少且固定
- 业务逻辑与分片键强关联
使用示例:
分片1:region = 'North'
分片2:region = 'South'
分片3:region = 'East'
分片4:region = 'West'复合分片
功能:结合多种分片策略,如先按范围分片,再按哈希分片
优点:
- 结合多种策略的优点
- 更灵活的分片方式
缺点:
- 增加了系统复杂度
- 分片规则设计复杂
适用场景:
- 复杂的业务场景
- 需要同时支持范围查询和精确查询
分库分表中间件
MySQL Proxy
功能:MySQL官方提供的中间件,用于实现读写分离和负载均衡
特点:
- 轻量级,部署简单
- 支持读写分离
- 支持负载均衡
- 扩展性有限
- 性能一般
MyCAT
功能:开源的分库分表中间件,支持MySQL、Oracle、DB2等多种数据库
特点:
- 支持垂直拆分和水平拆分
- 支持多种分片策略
- 支持读写分离
- 支持事务处理
- 社区活跃,文档丰富
ShardingSphere
功能:Apache开源的分布式数据库中间件,提供分库分表、读写分离、分布式事务等功能
特点:
- 模块化设计,灵活扩展
- 支持多种分片策略
- 支持分布式事务
- 支持读写分离
- 支持数据加密
- 支持SQL审计
Vitess
功能:Google开源的分布式数据库中间件,用于大规模MySQL部署
特点:
- 支持水平分片
- 支持自动扩容
- 支持读写分离
- 支持分布式事务
- 适合大规模部署
Atlas
功能:奇虎360开源的分库分表中间件,基于MySQL Proxy开发
特点:
- 支持读写分离
- 支持水平分片
- 支持负载均衡
- 部署简单
- 性能较好
分库分表设计原则
1. 业务驱动原则
- 根据业务需求设计分库分表策略
- 考虑业务增长趋势
- 考虑业务查询模式
- 考虑业务数据特点
2. 分片键选择原则
- 选择频繁用于查询条件的列
- 选择高基数的列
- 选择分布均匀的列
- 考虑范围查询的需求
- 考虑分片的扩展性
3. 数据分布原则
- 确保数据均匀分布到各个分片
- 避免热点数据集中在某个分片
- 考虑分片的存储容量
- 考虑分片的负载均衡
4. 可用性原则
- 确保系统高可用
- 考虑故障恢复机制
- 考虑数据备份和恢复策略
- 考虑分片的容错能力
5. 可扩展性原则
- 支持平滑扩容
- 支持在线分片调整
- 支持新增分片而不影响现有业务
- 考虑未来业务增长的需求
分库分表实现步骤
1. 需求分析
- 分析业务需求和数据特点
- 确定分库分表的目标
- 评估当前系统的性能瓶颈
- 预测未来业务增长趋势
2. 设计分片策略
- 选择合适的分片键
- 确定分片方式(垂直拆分或水平拆分)
- 选择分片算法
- 设计分片规则
3. 选择中间件
- 评估各种中间件的特点和性能
- 选择适合业务需求的中间件
- 设计中间件的部署架构
4. 数据迁移
- 设计数据迁移方案
- 执行数据迁移
- 验证数据一致性
- 切换业务流量
5. 系统测试
- 测试系统性能
- 测试系统可用性
- 测试故障恢复机制
- 测试数据一致性
6. 上线部署
- 灰度发布
- 监控系统运行状态
- 优化系统性能
- 制定应急预案
分库分表常见问题
1. 跨分片查询
问题:需要查询多个分片的数据,导致查询性能下降
解决方案:
- 优化查询语句,减少跨分片查询
- 使用中间件支持的全局索引
- 考虑数据冗余,避免跨分片查询
- 使用分布式查询引擎
2. 分布式事务
问题:需要保证多个分片上的数据一致性
解决方案:
- 使用中间件支持的分布式事务
- 采用最终一致性方案
- 使用消息队列保证数据一致性
- 设计幂等操作,避免重复执行
3. 数据迁移
问题:数据迁移过程中可能影响业务运行
解决方案:
- 设计在线数据迁移方案
- 使用双写策略,确保数据一致性
- 进行充分的测试和验证
- 选择业务低峰期进行迁移
4. 扩容问题
问题:扩容过程中需要重新分配数据
解决方案:
- 设计支持平滑扩容的分片策略
- 使用中间件支持的在线扩容
- 考虑预分片策略,提前规划分片数量
- 采用一致性哈希算法,减少数据迁移量
5. 主键冲突
问题:多个分片可能产生相同的主键
解决方案:
- 使用全局唯一ID生成器(如Snowflake算法)
- 使用UUID
- 使用数据库自增主键 + 分片ID
- 使用中间件支持的全局主键
最佳实践
1. 优先考虑垂直拆分
- 垂直拆分相对简单,风险较低
- 可以解决大部分性能问题
- 便于后续水平拆分
2. 合理选择分片键
- 分片键的选择直接影响系统性能
- 考虑查询模式和数据分布
- 避免频繁修改分片键
- 考虑分片的扩展性
3. 控制分片数量
- 分片数量不宜过多,否则增加系统复杂度
- 根据业务需求和硬件资源调整分片数量
- 考虑分片的管理和维护成本
4. 避免跨分片事务
- 跨分片事务增加系统复杂度
- 影响系统性能
- 考虑业务设计,减少跨分片事务
- 使用最终一致性方案
5. 监控和优化
- 监控分片的性能和负载
- 监控数据分布情况
- 定期优化分片策略
- 定期清理无用数据
垂直拆分与水平拆分对比
| 特性 | 垂直拆分 | 水平拆分 |
|---|---|---|
| 拆分方式 | 按列拆分 | 按行拆分 |
| 表结构 | 不同表结构 | 相同表结构 |
| 适用场景 | 表包含大字段、列访问频率差异大 | 表数据量大、查询性能下降 |
| 复杂度 | 相对较低 | 相对较高 |
| 扩容方式 | 独立扩容 | 横向扩容 |
| 跨分片查询 | 可能需要跨表join | 可能需要跨分片查询 |
| 事务处理 | 相对简单 | 相对复杂 |
| 数据一致性 | 容易维护 | 维护难度大 |
分库分表案例分析
案例1:电商系统订单表设计
问题:订单表数据量过大,查询性能下降
解决方案:
- 垂直拆分:将订单表拆分为订单核心表和订单扩展表
- 水平拆分:按订单创建时间范围进行分片
- 分片策略:
- 按年分片:每年创建一个订单表
- 热点数据:最近3个月的数据放在一个分片,便于快速访问
- 中间件选择:使用ShardingSphere实现分库分表
效果:
- 查询性能提升300%
- 支持系统的快速扩展
- 便于维护和管理
案例2:社交系统用户表设计
问题:用户表数据量超过1亿,插入和查询性能下降
解决方案:
- 垂直拆分:将用户表拆分为用户核心表和用户详细信息表
- 水平拆分:按用户ID哈希分片
- 分片策略:
- 使用一致性哈希算法,减少扩容时的数据迁移
- 分片数量:64个分片
- 中间件选择:使用MyCAT实现分库分表
效果:
- 插入性能提升200%
- 查询性能提升500%
- 支持系统的线性扩展
常见问题(FAQ)
Q1: 什么时候需要考虑分库分表?
A1: 以下情况需要考虑分库分表:
- 单表数据量超过1000万行
- 查询性能明显下降
- 写入性能明显下降
- 数据库存储空间不足
- 系统需要支持更高的并发
Q2: 垂直拆分和水平拆分的区别是什么?
A2: 垂直拆分和水平拆分的主要区别:
- 垂直拆分按列拆分,水平拆分按行拆分
- 垂直拆分后表结构不同,水平拆分后表结构相同
- 垂直拆分解决表复杂度问题,水平拆分解决数据量问题
- 垂直拆分相对简单,水平拆分相对复杂
Q3: 如何选择合适的分片键?
A3: 选择合适的分片键需要考虑以下因素:
- 频繁用于查询条件的列
- 高基数的列
- 分布均匀的列
- 便于范围查询的列
- 考虑分片的扩展性
Q4: 分库分表后如何处理跨分片查询?
A4: 处理跨分片查询的方法:
- 优化查询语句,减少跨分片查询
- 使用中间件支持的全局索引
- 考虑数据冗余,避免跨分片查询
- 使用分布式查询引擎
Q5: 分库分表后如何保证数据一致性?
A5: 保证数据一致性的方法:
- 使用中间件支持的分布式事务
- 采用最终一致性方案
- 使用消息队列保证数据一致性
- 设计幂等操作,避免重复执行
Q6: 如何选择合适的分库分表中间件?
A6: 选择合适的分库分表中间件需要考虑以下因素:
- 业务需求和场景
- 中间件的功能和特性
- 中间件的性能和稳定性
- 中间件的社区活跃度和文档支持
- 团队的技术栈和经验
Q7: 分库分表后如何进行数据迁移?
A7: 数据迁移的步骤:
- 设计数据迁移方案
- 执行数据迁移
- 验证数据一致性
- 切换业务流量
Q8: 分库分表后如何进行扩容?
A8: 扩容的方法:
- 设计支持平滑扩容的分片策略
- 使用中间件支持的在线扩容
- 考虑预分片策略,提前规划分片数量
- 采用一致性哈希算法,减少数据迁移量
Q9: 分库分表会影响系统的可用性吗?
A9: 分库分表可能会影响系统的可用性,因此需要:
- 确保系统高可用
- 考虑故障恢复机制
- 考虑数据备份和恢复策略
- 考虑分片的容错能力
Q10: 分库分表后如何监控系统性能?
A10: 监控系统性能的方法:
- 监控分片的性能和负载
- 监控数据分布情况
- 监控查询响应时间
- 监控系统资源使用情况
- 定期进行性能测试和优化
