MySQL 分库分表:数据库的"豪宅改造计划"

MySQL 分库分表:数据库的"豪宅改造计划" ?️

当你的单身公寓住不下所有家具时,你会怎么做?搬到大房子或者拆分成多个小仓库!MySQL 的数据也有同样的烦恼...

什么是分库分表??

分库分表是指将原本存储在单个数据库和单张表中的数据,按照特定的规则切分到多个数据库或多个表中,以解决海量数据存储和访问的性能问题。简单来说:当数据量太大,一个"房子"住不下时,要么买更多房子(分库),要么在同一个房子里隔出更多房间(分表)。

为什么要"搬家"??

场景:拥挤的公寓
数据库:"我实在太拥挤了,每次查询都要翻箱倒柜!"
DBA:"是时候搬家或者做个大扩建了!"
开发者:"但搬家好麻烦啊..."
DBA:"比你的系统崩溃容易处理多了!"

主要原因

  • 单表数据量过大 - 一张表超过千万级别,查询性能急剧下降
  • 并发访问压力大 - 一个 MySQL 实例扛不住高并发
  • 存储容量受限 - 单机硬盘总有极限
  • 备份恢复时间长 - 几百 G 的数据备份一次要到天亮

分库分表的两大流派 ?

1️. 垂直拆分 - "按功能区分不同的房子"

场景:家庭空间规划
家长:"厨房用品放厨房,卧室用品放卧室,不要混在一起!"
数据表:"我们按业务功能分开住,互不干扰!"

垂直分库

做法:按业务模块将不同表拆分到不同的数据库中
案例:用户库、订单库、商品库分开部署

搬家前:
┌────────────────────┐
│ 大杂烩数据库 │
│ ┌──────┐ ┌──────┐ │
│ │用户表 │ │订单表 │ │
│ └──────┘ └──────┘ │
│ ┌──────┐ ┌──────┐ │
│ │商品表 │ │评论表 │ │
│ └──────┘ └──────┘ │
└────────────────────┘
搬家后:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户库 │ │ 订单库 │ │ 商品库 │
│ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │
│ │用户表 │ │ │ │订单表 │ │ │ │商品表 │ │
│ └──────┘ │ │ └──────┘ │ │ └──────┘ │
└──────────┘ └──────────┘ └──────────┘

垂直分表

做法:将一张表中的列分拆到多张表,常用字段放一起,不常用字段另开表
案例:商品基本信息表、商品详细描述表、商品图片表

分表前:
┌─────────────────── 商品表 ───────────────────┐
│ ID │ 名称 │ 价格 │ 库存 │ 详细描述 │ 图片URL集 │
└─────────────────────────────────────────────┘
分表后:
┌─────── 商品基本表 ──────┐ ┌── 商品描述表 ──┐ ┌── 商品图片表 ───┐
│ ID │ 名称 │ 价格 │ 库存 │ │ ID │ 详细描述 │ │ ID │ 图片URL集 │
└───────────────────────┘ └───────────────┘ └───────────────┘

2️. 水平拆分 - "同样的房子造多个小区"

场景:小区扩建
开发商:"一个小区住不下这么多人,我们再建5个一模一样的!"
居民:"新小区和旧小区户型完全一样,只是地址不同!"

水平分库

做法:同一个表的数据拆分到不同数据库中
案例:订单库 1、订单库 2、订单库 3...

分库前:
┌────── MySQL实例 ──────┐
│ 订单库 │
│ ┌───────────┐ │
│ │ 订单表 │ │
│ │(1千万数据) │ │
│ └───────────┘ │
└───────────────────────┘
分库后:
┌─── 实例1 ───┐ ┌─── 实例2 ───┐ ┌─── 实例3 ──┐
│ 订单库1 │ │ 订单库2 │ │ 订单库3 │
│ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────┐ │
│ │订单表 │ │ │ │订单表 │ │ │ │订单表 │ │
│ │(300万)│ │ │ │(400万) │ │ │ │(300万)│ │
│ └───────┘ │ │ └───────┘ │ │ └───────┘ │
└────────────┘ └─────────────┘ └───────────┘

水平分表

做法:同一个数据库中的表拆分成多个表,结构完全相同
案例:订单表_0、订单表_1、...、订单表_9

分表前:
┌────────── 订单表 ─────────┐
│ order_id │ user_id │ ... │
│ 10001 │ 2103 │ ... │
│ 10002 │ 5832 │ ... │
│ ... │ ... │ ... │
└──────────────────────────┘
分表后:
┌── 订单表_0 ─┐ ┌── 订单表_1 ─┐ ┌── 订单表_9 ─┐
│id │user│...│ │id │user│...│ ... │id │user│...│
│...│ .. │...│ │...│ .. │...│ │...│ .. │...│
└────────────┘ └────────────┘ └────────────┘

分片策略:"如何决定谁住哪儿" ?️

1. 哈希分片 - "按门牌号分配"

应用:"订单1234应该放在哪个库?"
路由层:"1234 % 4 = 2,所以放在2号库!"

特点

  • 均匀分布数据
  • 扩容麻烦,需要 rehash
  • 不适合范围查询

2. 范围分片 - "按街区划分"

应用:"ID为80万的用户应该放哪里?"
路由层:"50万~100万的用户在2号库,所以放2号库!"

特点

  • 扩容简单
  • 数据分布可能不均
  • 适合范围查询

3. 时间分片 - "按入住日期划分"

应用:"2023年1月的订单要查哪里?"
路由层:"查订单_202301表就行了!"

特点

  • 历史数据归档方便
  • 新数据集中在最新表
  • 适合按时间查询

4. 列表分片 - "VIP 客户走专属通道"

应用:"北京的用户数据在哪?"
路由层:"查表_北京就行了!"

特点

  • 按特定业务属性分片
  • 适合有明显区分的业务
  • 数据分布不均

同构 VS 异构:房子风格不同了 ?️

1. 相同表结构(同构)

所有分片表结构完全相同,就像同一个小区的不同楼栋。

CREATE TABLE orders_0 (id INT, user_id INT, ...);
CREATE TABLE orders_1 (id INT, user_id INT, ...);
...

2. 不同表结构(异构)

分片后表结构有差异,就像别墅区和普通住宅区。

-- VIP用户表(多了信用额度)
CREATE TABLE vip_users (id INT, name VARCHAR(50), credit DECIMAL, ...);
-- 普通用户表
CREATE TABLE normal_users (id INT, name VARCHAR(50), ...);

分库分表的"搬家难题" ?

1. 分布式事务 - "多个房子的装修需要统一协调"

场景:跨库操作
应用:"我需要同时更新用户账户和订单状态,它们在不同的库!"
DBA:"这...要么妥协用最终一致性,要么引入分布式事务框架..."

解决方案

  • 柔性事务(最终一致性)
  • XA 事务
  • 消息队列

2. 跨库关联 - "朋友分别住在不同小区"

场景:跨库JOIN
应用:"我需要查用户购买的所有商品,但用户表和订单表不在一个库!"
DBA:"你只能在应用层先查一个库,再查另一个库,然后手动'JOIN'了..."

解决方案

  • 冗余字段(反范式化)
  • 数据字典表
  • 应用层组装

3. 全局唯一 ID - "不同小区门牌号不能重复"

场景:订单ID生成
应用:"不同的订单库,怎么保证订单ID不重复?"
DBA:"忘掉自增主键吧,我们需要其他方案..."

解决方案

  • UUID
  • 雪花算法(Snowflake)
  • 集中式 ID 生成器
  • 号段模式

4. 动态扩容 - "小区不够住了还要加新楼"

场景:数据量增长
DBA:"现有的8个分库又满了,需要增加到16个..."
开发:"所有数据要重新分配位置?那路由规则不是全变了?"
DBA:"准备加班吧,朋友..."

解决方案

  • 一致性哈希
  • 双写过渡
  • 数据迁移工具

常见分库分表中间件 ?

就像搬家公司,它们帮你处理复杂的路由和迁移:

  1. Sharding-JDBC - 轻量级 Java 框架,像个小型搬家团队
  2. MyCat - 强大的中间代理,像个专业搬家公司
  3. DynamoDB - AWS 提供的全托管方案,像个帮你包办一切的豪华搬家服务
  4. Vitess - YouTube 开源的可扩展 MySQL 集群系统,像个大型物流集团

分库分表最佳实践 ?

1. 先分表后分库

阶段1:单库单表 → 单库多表
阶段2:单库多表 → 多库多表

就像先在自家隔出更多房间,实在不行再买新房子。

2. 避免过度设计

数据量:< 100万,别分
 100万~1000万,考虑分表
 > 1000万,考虑分库分表

小别墅住 3 个人,没必要隔出 10 个房间。

3. 尽量避免跨库 JOIN

-- 避免这样
SELECT u.name, o.order_id FROM users u
JOIN orders o ON u.id = o.user_id;
-- 改为两次查询
SELECT id, name FROM users WHERE id = ?;
SELECT order_id FROM orders WHERE user_id = ?;

朋友住不同小区,就别老想着办集体 party 了。


"数据库就像是你的房子,当东西太多时,你有两个选择:买更大的房子,或者更好地整理现有空间。分库分表是整理的艺术,而不仅仅是简单地买更多房子。"

—— 匿名架构师


下次面试官问你 MySQL 分库分表,别慌!告诉他:那不过是数据库世界的"乔迁新居"罢了!?

作者:科韵小栈原文地址:https://www.cnblogs.com/geeklab/p/18805437

%s 个评论

要回复文章请先登录注册