数据库分片:MySQL分库分表实战
大家好,我是欧阳瑞(Rich Own)。今天想和大家聊聊数据库分片这个重要话题。作为一个全栈开发者,当数据量增长到一定规模时,数据库分片是必不可少的优化手段。今天就来分享一下MySQL分库分表的实战经验。
为什么需要分片?
数据增长挑战
| 问题 | 说明 |
|---|---|
| 单表数据过大 | 查询性能下降 |
| 单库压力过大 | 无法水平扩展 |
| 备份恢复困难 | 数据量大导致备份时间长 |
分片策略
水平分片 → 按行拆分
垂直分片 → 按列拆分
混合分片 → 结合水平和垂直
分片方案
1. 按范围分片
按时间范围:202401, 202402, 202403...
按ID范围:1-1000000, 1000001-2000000...
2. 按哈希分片
user_id % 100 → 0-99个分片
使用一致性哈希
3. 按业务分片
按地区:北京、上海、广州...
按业务线:订单、用户、商品...
实战案例
分表实现
sql
-- 创建分片表
CREATE TABLE user_0 (
id BIGINT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
created_at TIMESTAMP
);
CREATE TABLE user_1 (
id BIGINT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
created_at TIMESTAMP
);
-- 分片函数
DELIMITER //
CREATE FUNCTION get_user_shard(user_id BIGINT)
RETURNS INT
DETERMINISTIC
BEGIN
RETURN user_id % 2;
END //
DELIMITER ;
中间件方案
javascript
// 使用ShardingSphere
const ShardingSphere = require('shardingsphere-jdbc');
const shardingRule = {
tables: {
user: {
actualDataNodes: 'ds_${0..1}.user_${0..1}',
databaseStrategy: {
standard: {
shardingColumn: 'id',
shardingAlgorithmName: 'database_inline'
}
},
tableStrategy: {
standard: {
shardingColumn: 'id',
shardingAlgorithmName: 'table_inline'
}
}
}
}
};
代码层面分片
javascript
class ShardedUserRepository {
constructor() {
this.shards = [db0, db1, db2, db3];
}
getShardIndex(userId) {
return userId % this.shards.length;
}
async getUser(userId) {
const shardIndex = this.getShardIndex(userId);
return this.shards[shardIndex].query('SELECT * FROM user WHERE id = ?', [userId]);
}
async createUser(user) {
const shardIndex = this.getShardIndex(user.id);
return this.shards[shardIndex].query('INSERT INTO user SET ?', user);
}
}
注意事项
事务处理
跨分片事务 → 使用分布式事务(2PC、TCC)
尽量避免跨分片操作
数据迁移
在线迁移 → 使用工具如gh-ost
双写策略 → 同时写入新旧分片
扩容问题
使用一致性哈希 → 减少数据迁移
预留分片空间 → 避免频繁扩容
总结
数据库分片是处理大规模数据的有效手段。通过合理的分片策略和中间件支持,可以实现数据库的水平扩展。
我的鬃狮蜥Hash对分片也有自己的理解------它总是把蟋蟀分成不同区域管理,这也许就是自然界的"分片策略"吧!
如果你对数据库分片有任何问题,欢迎留言交流!我是欧阳瑞,极客之路,永无止境!
技术栈:MySQL · 分库分表 · 数据库优化