数据库分库分表详解与实践
一、分库分表
1. 什么是分库分表
分库分表是将一个大型数据库中的数据分散存储到多个数据库或表中的技术方案,目的是解决单库单表数据量过大导致的性能瓶颈问题。
2. 为什么要分库分表
- 性能瓶颈:单表数据量过大导致查询性能下降
- 连接数限制:单库连接数有限
- 存储限制:单机存储容量有限
- 高可用需求:分散风险,提高系统可用性
二、分库分表策略
1. 水平分表(横向拆分)
将同一个表的数据按行拆分到不同的表中,所有表结构相同。
适用场景:
- 单表数据量过大
- 表数据有自然分割点(如时间、地域)
实现方式:
-- 原始表
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT,
amount DECIMAL(10,2),
create_time DATETIME
);
-- 分表后
CREATE TABLE orders_0 (同结构);
CREATE TABLE orders_1 (同结构);
2. 垂直分表(纵向拆分)
将同一个表的不同字段拆分到不同的表中。
适用场景:
- 表字段多,且部分字段不常用
- 有超大字段(如TEXT/BLOB)
实现方式:
-- 原始表
CREATE TABLE user (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(100),
profile TEXT,
login_time DATETIME
);
-- 分表后
CREATE TABLE user_basic (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(100),
login_time DATETIME
);
CREATE TABLE user_profile (
user_id BIGINT PRIMARY KEY,
profile TEXT
);
3. 分库策略
将表分散到不同的数据库中。
常见策略:
- 按业务模块分库(订单库、用户库)
- 按数据特征分库(华北库、华南库)
- 按哈希取模分库
三、分库分表实现方案
1. 客户端分片
在应用层实现分片逻辑,如MyBatis+自定义路由。
优点:灵活可控
缺点:侵入性强,维护成本高
2. 中间件分片
使用分库分表中间件:
- ShardingSphere:Apache开源项目,功能全面
- MyCat:基于Proxy的中间件
- TDDL:阿里开源分布式数据库层
3. 数据库原生支持
- MySQL Cluster
- PostgreSQL分区表
- MongoDB分片集群
四、分片键选择
1. 选择原则
- 数据分布均匀:避免热点
- 查询常用:减少跨库查询
- 避免频繁修改:减少数据迁移
2. 常用分片键
- 用户ID
- 订单ID
- 时间范围
- 地理区域
五、分库分表带来的问题与解决方案
1. 分布式事务
解决方案:
- 最终一致性
- TCC模式
- 本地消息表
- Seata等分布式事务框架
2. 跨库JOIN
解决方案:
- 数据冗余
- 应用层组装
- 使用宽表
- 异构索引(如Elasticsearch)
3. 全局ID生成
解决方案:
- UUID(简单但无序)
- 数据库自增序列(需中心化)
- Snowflake算法(推荐)
- Leaf(美团开源)
4. 扩容问题
解决方案:
- 预留分片(提前规划)
- 一致性哈希(减少数据迁移)
- 双写迁移(平滑过渡)
六、实践
1. 何时考虑分库分表
- 单表数据量超过500万(非)
- 查询性能明显下降
- 索引优化已到极限
2. 分片数量规划
- 考虑未来3-5年增长
- 单表建议控制在500万-1000万数据量
- 分库数量考虑服务器资源
3. 监控与维护
- 建立分片健康监控
- 定期检查数据分布
- 准备扩容方案
4. 代码设计建议
// 使用ShardingSphere示例配置
spring:
shardingsphere:
datasource:
names: ds0,ds1
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: t_order_$->{order_id % 2}
database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds$->{user_id % 2}
分库分表是解决数据库扩展性的重要手段,但会带来系统复杂度的提升。实施前应充分评估需求,选择合适的策略和工具,并做好应对各种挑战的准备。对于新系统,建议从设计初期就考虑分片策略;对于现有系统,应制定详细的迁移方案。