首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >分库分表之策略

分库分表之策略

作者头像
工藤学编程
发布2025-12-22 09:04:12
发布2025-12-22 09:04:12
1000
举报

大家好,我是工藤学编程 🦉

一个正在努力学习的小博主,期待你的关注

实战代码系列最新文章😉

C++实现图书管理系统(Qt C++ GUI界面版)

SpringBoot实战系列🐷

【SpringBoot实战系列】Sharding-Jdbc实现分库分表到分布式ID生成器Snowflake自定义wrokId实战

环境搭建大集合

环境搭建大集合(持续更新)

分库分表

分库分表之数据库分片分类


前情摘要:

1、数据库性能优化 2、分库分表之优缺点分析 3、分库分表之数据库分片分类

MySQL水平分库分表策略:RANGE范围拆分详解

一、RANGE范围拆分的核心逻辑

RANGE拆分是按数据主键的取值范围将数据划分到不同分表/分库中,本质是通过区间分段实现数据分片。其核心规则是定义连续的区间段,每个区间对应一个分片,典型应用场景包括:

  • 日志类业务(如交易日志、操作日志):数据按时间顺序产生,且历史数据查询频率低,新数据访问频繁。
  • 时效性强的业务(如订单、活动记录):需优先保证近期数据的查询性能,历史数据可归档。
  • 数据增长可预测的场景:如按月/年生成的数据报表,可预先规划分库分表区间。
  • 空间维度业务(如多地域数据、云服务器节点数据):需按物理位置或服务节点划分数据,实现本地化访问与故障隔离。

二、RANGE拆分的具体实现方案

1.自增ID范围分表案例

以订单表为例,基于自增IDorder_id进行RANGE拆分:

代码语言:javascript
复制
分片规则:
table_1: order_id ∈ [1, 1000000)
table_2: order_id ∈ [1000000, 2000000)
table_3: order_id ∈ [2000000, 3000000)
...
table_n: order_id ∈ [(n-1)*1000000, n*1000000)

建表示例

代码语言:javascript
复制
CREATE TABLE `order_01` (
  `order_id` bigint(20) NOT NULL COMMENT '订单ID(1-100万)',
  `user_id` bigint(20) NOT NULL,
  `create_time` datetime NOT NULL,
  -- 其他字段
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB CHARSET=utf8;

CREATE TABLE `order_02` (
  `order_id` bigint(20) NOT NULL COMMENT '订单ID(100万-200万)',
  `user_id` bigint(20) NOT NULL,
  `create_time` datetime NOT NULL,
  -- 其他字段
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB CHARSET=utf8;
2. 时间范围分库方案

按时间粒度(年/月/日)拆分数据库,适用于日志、交易等有时间序列特征的数据:

代码语言:javascript
复制
分库规则:
log_2024: 存储2024年全年日志
log_2023: 存储2023年全年日志
log_2022: 存储2022年全年日志
在这里插入图片描述
在这里插入图片描述

核心SQL路由逻辑

代码语言:javascript
复制
// 根据日志时间确定分库
String year = dateFormat.format(logTime);
String dbName = "log_" + year;
3. 空间范围分库分表方案

按物理位置、云服务器节点或地域属性拆分,实现数据本地化存储:

代码语言:javascript
复制
分库规则(按地域):
db_beijing: 华北地区数据(order_id ∈ [1, 1000万))
db_shanghai: 华东地区数据(order_id ∈ [1000万, 2000万))
db_guangzhou: 华南地区数据(order_id ∈ [2000万, 3000万))

分表规则(按服务器节点):
table_node1: 服务器A数据(order_id % 3 = 0)
table_node2: 服务器B数据(order_id % 3 = 1)
table_node3: 服务器C数据(order_id % 3 = 2)
在这里插入图片描述
在这里插入图片描述

核心路由逻辑(地域+ID复合)

代码语言:javascript
复制
// 1. 按地域划分大区间
String region = getRegionByUserIp(userIp);
int regionBaseId = regionMap.get(region); // 华北=0,华东=1000万,华南=2000万

// 2. 按ID范围分库
long orderId = ...;
int dbIndex = (int)((orderId - regionBaseId) / 10000000);
String dbName = "db_" + region + "_" + dbIndex;

三、RANGE拆分的三大核心优势

  1. 扩容无数据迁移成本
    • 新增分片只需定义新区间(如table_n+1对应[n*100万, (n+1)*100万)),无需移动历史数据。
    • 案例:当table_10写满后,直接创建table_11并配置区间,新数据自动写入新表。
  2. 规则简单易维护
    • 无需复杂算法,仅需维护区间映射关系,开发与运维成本低。
    • 适用场景:中小团队或初期项目,快速落地分库分表。
  3. 历史数据归档便捷
    • 可按时间范围将冷数据(如3年前日志)迁移至低成本存储,热数据(近1年)保留在高性能集群。
    • 空间场景延伸:按地域归档数据,如将海外用户数据迁移至本地合规存储节点。

四、不可忽视的四大应用痛点

问题类型

具体表现

影响程度

数据热点集中

最新区间(如table_n)或热点地域(如北上广分库)承担90%以上读写请求,导致单表/单库IO瓶颈

★★★★★

资源利用率低

历史区间(如table_1)或非热点地域分库数据极少被访问,硬件资源浪费

★★★☆☆

跨分片查询复杂

范围查询(如order_id > 500万)或跨地域统计需扫描多个分片,性能随分片数增加而下降

★★★☆☆

区间边界设计困难

区间大小难以预估:过小导致分片数激增,过大导致单表数据量再次超限;空间维度中地域流量不均衡可能导致分库负载失衡

★★★★☆

Hash取模分库分表策略:均匀分布与扩容挑战详解

一、Hash取模的核心原理与实现逻辑

Hash取模是通过对分片字段(如用户ID、订单ID)进行哈希计算后取模,将数据均匀分配到不同库表中。其核心逻辑是利用哈希函数的离散性,确保数据在分片节点上的均衡分布,典型应用场景包括:

  • 用户维度强相关业务(如用户中心、订单系统):需保证同一用户数据集中在同一库表;
  • 高并发且数据访问均匀的场景(如社交平台消息表):避免单节点热点集中。
二、Hash取模的具体实现方案
1. 整数型字段直接取模案例

以用户ID分库分表为例,目标是拆分为2个库,每个库包含4张表(共8张表):

代码语言:javascript
复制
分片规则:
库路由:db_idx = userId % 2  
表路由:table_idx = (userId / 2) % 4  
注:为什么table_idx不直接(userId ) % 4 呢?
这种方式会导致每个数据库会存储所有表的一部分数据,并且不同数据库里相同表索引的表所存数据是不一样的。这将可能导致数据不均匀的情况。
示例验证
假设用户 ID 为偶数(如 2、4、6):
策略table_idx =(userId ) % 4:这些 ID 会被分到不同的表中,例如 2 → 表 2,4 → 表 0,6 → 表 2。
策略table_idx = (userId / 2) % 4:这些 ID 会被分到同一张表,例如 2 → 表 1,4 → 表 2,6 → 表 3。
可以看到,我们提出的策略将会使得数据更加均匀
直接取模的缺陷
userId % 4 的结果仅由 ID 末两位决定(二进制角度),当 ID 按奇偶分段(如分 2 库)时,偶数 ID 的末两位可能集中在 00、10 等模式,导致取模结果偏向特定值(如策略一中偶数 ID%4 结果多为 0 或 2)。
先除再取模的原理
将 ID 除以 2(userId / 2)相当于将 ID 范围「压缩」一半,例如:
原 ID 范围:2,4,6,8,10,12 → 压缩后:1,2,3,4,5,6
压缩后的数值对 4 取模,等价于将原 ID 范围按每 8 个 ID(2 库 ×4 表)为一组重新分段,每组内的 ID 会均匀分布到 4 张表:
组 1(ID=2-9):压缩后 1-4 → %4 得 1,2,3,0
组 2(ID=10-17):压缩后 5-8 → %4 得 1,2,3,0
在这里插入图片描述
在这里插入图片描述

数据路由示例

userId

db_idx(库)

table_idx(表)

目标库表

1

1%2=1

(1/2)=0 → 0%4=0

db_1.table_0

2

2%2=0

(2/2)=1 → 1%4=1

db_0.table_1

8

8%2=0

(8/2)=4 → 4%4=0

db_0.table_0

9

9%2=1

(9/2)=4 → 4%4=0

db_1.table_0

建表示例

代码语言:javascript
复制
-- 库1(db_1)中的表
CREATE TABLE `user_0` ( ... );  -- table_idx=0
CREATE TABLE `user_1` ( ... );  -- table_idx=1
CREATE TABLE `user_2` ( ... );  -- table_idx=2
CREATE TABLE `user_3` ( ... );  -- table_idx=3

-- 库2(db_2)中的表
CREATE TABLE `user_0` ( ... );  -- table_idx=0
CREATE TABLE `user_1` ( ... );  -- table_idx=1
CREATE TABLE `user_2` ( ... );  -- table_idx=2
CREATE TABLE `user_3` ( ... );  -- table_idx=3
2. 非整数型字段哈希取模方案

当分片字段为字符串(如手机号、邮箱)时,需先通过哈希函数转为整数再取模:

代码语言:javascript
复制
// 手机号分库分表示例
String phone = "13800138000";
int hashCode = phone.hashCode();  // 转为哈希值
int dbIdx = Math.abs(hashCode) % 2;  // 库路由
int tableIdx = Math.abs(hashCode) / 2 % 4;  // 表路由

哈希函数选择建议

  • 轻量级场景:使用Java原生hashCode()或Pythonhash()
  • 高并发场景:采用MurmurHashFNVHash等高性能哈希算法,降低哈希冲突概率。

三、Hash取模的核心优势

  1. 数据均匀分布,避免热点集中
    • 通过哈希取模,数据在各库表间的分布偏差可控制在5%以内。
    • 案例:1000万用户ID取模分8张表,每张表数据量在124万-126万之间,无明显倾斜。
  2. 单用户数据聚合,查询效率高
    • 同一用户的所有数据(如订单、信息)集中在同一库表,避免跨库JOIN。
    • 场景:查询用户订单时,仅需访问单个库表,无需聚合多节点数据。
  3. 规则简单,适合高并发场景
    • 路由逻辑可在应用层快速计算,无需查询配置表,响应时间稳定在1ms以内。

四、不可忽视的扩容痛点与解决方案

问题类型

具体表现

影响程度

扩容需全量数据迁移

从N库扩至2N库时,需重新计算所有数据的%2N,并迁移至新库

★★★★★

迁移期间服务波动

全量迁移需停机或读写分离,可能导致分钟级至小时级服务不可用

★★★★☆

哈希冲突风险

不同字段哈希后取模结果相同(如手机号13800138000与13900139000哈希值相同)

★★☆☆☆

Hash取模作为最常用的分库分表策略,通过简单规则实现数据均匀分布,尤其适合用户维度强相关的高并发场景。尽管存在扩容成本高的缺点,但通过复合拆分策略与中间件优化,可在数据均衡性与可扩展性之间找到平衡点,是互联网业务落地分库分表的首选方案之一。

总结

在这里插入图片描述
在这里插入图片描述

分片策略对比:

在这里插入图片描述
在这里插入图片描述

扩展阅读MySQL官方分库分表方案

觉得有用请点赞收藏! 如果有分库分表相关问题,欢迎评论区留言讨论~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MySQL水平分库分表策略:RANGE范围拆分详解
    • 一、RANGE范围拆分的核心逻辑
    • 二、RANGE拆分的具体实现方案
    • 三、RANGE拆分的三大核心优势
    • 四、不可忽视的四大应用痛点
  • Hash取模分库分表策略:均匀分布与扩容挑战详解
    • 一、Hash取模的核心原理与实现逻辑
      • 二、Hash取模的具体实现方案
    • 三、Hash取模的核心优势
    • 四、不可忽视的扩容痛点与解决方案
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档