分库分表--为什么(1)

8 阅读6分钟

1.什么是分库分表

分库解决的是"流量瓶颈"(如连接数、CPU、IO压力),分表解决的是"数据量瓶颈"(B+树层数增加) 分库:就是一个数据库分成多个数据库,部署到不同机器。

  • 优点
    • 业务层面的耦合,业务清晰
    • 不同业务的数据进行分级管理、维护、监控、扩展
    • 提升IO、数据库连接数、降低单机硬件资源的瓶颈
  • 缺点:
    • 相对单系统维护比较麻烦,运维成本大
    • 分布式事务
    • 跨库操作:JOIN 查询需应用层拼接(N+1查询)或冗余字段、聚合函数 SELECT SUM(amount) 需分别查各库再内存聚合、唯一约束需全局ID生成器 image.png 分表:就是一个数据库表分成多个表。 image.png

2.为什么分库分表

 解决三大瓶颈问题

  • 数据量瓶颈:单表数据量超过1000万行后,索引性能急剧下降,查询耗时显著增加;单库磁盘空间达到TB级时,备份和恢复变得困难。
  • 并发瓶颈:MySQL单机的并发连接数有限(查看最大连接数:SELECT @@max_connections; 查看当前活跃查询线程数:SHOW STATUS LIKE 'Threads_running'; ),高并发场景下会出现连接阻塞、超时等问题。
  • 性能瓶颈:频繁的读写操作导致磁盘IO和CPU负载过高,即使优化索引和SQL,性能提升也难以满足业务需求。

提升系统能力

  • 提高系统的吞吐量和并发处理能力
  • 降低单点故障风险,提高系统可用性
  • 实现水平扩展,应对业务快速增长

重要前提:分库分表是最后的手段,不是首选方案。它会带来巨大的复杂性(如分布式事务、跨库查询等),应优先考虑优化(如索引优化、SQL优化、读写分离等)。

3.什么时候需要分库分表

3.1 分表

  • 阿里手册

阿里开发手册的MYSQL‘建表规约’中推荐单表超500W或容量超2GB才推荐分库分表。 image.png

  • 理论值计算

InnoDB 的最小 I/O 单位是 页(Page) ,默认大小为 16KB,所有数据(表数据、索引、undo 日志等)都以页为单位在磁盘和内存间读写。B+树叶子存的是数据,内部节点存的是键值+指针。索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中,进而再去数据页中找到需要的数据。

假设B+树的高度为2的话,即有一个根结点和若干个叶子结点。这棵B+树的存放总记录数为=根结点指针数*单个叶子节点记录行数。

如果一行记录的数据大小为1k,那么单个叶子节点可以存的记录数  =16k/1k =16. 非叶子节点内存放多少指针呢?我们假设主键ID为bigint类型,长度为8字节(int就是32位,4字节),而指针大小在InnoDB源码中设置为6字节,所以就是 8+6=14 字节,16k/14B =16*1024B/14B = 1170

因此,一棵高度为2的B+树,能存放1170^(2-1) * 16=18720条这样的数据记录。同理一棵高度为3的B+树,能存放1170^(3-1) *16 =21902400,大概可以存放两千万左右的记录。

B+树高度一般为1-3层,如果B+到了4层,查询的时候会多查磁盘的次数,SQL就会变慢。

即使B+树未达4层,出现以下情况也应分表:

-   单表大小 > 200GB(备份恢复困难)
-   简单查询耗时 > 1秒
-   ALTER TABLE等DDL操作耗时过长
-   写入QPS > 5000且主从延迟严重
  • 结论
    • 理论极限:≈2000万行(B+树3层容量)
    • 工程预警线:500万~1000万行(阿里手册+实战经验)
    • 分库分表是最后手段!  优先尝试:索引优化 + SQL调优、读写分离(读走从库,写走主库  → 解决读并发瓶颈)、冷热数据分离(归档历史数据)、垂直分表(拆分大字段)

3.2 分库

单机数据库资源达到物理上限

资源类型表现判断依据
CPU 持续 > 80%查询变慢、写入延迟即使 SQL 优化后仍无法缓解
磁盘 IO 饱和IOPS 打满、IO 等待时间高iostat -x 1 显示 %util > 90%
内存不足频繁 swap、buffer pool 命中率低InnoDB Buffer Pool 命中率 < 95%
网络带宽打满主从同步延迟、客户端超时千兆网卡持续跑满(≈120MB/s)
连接数/并发压力超过单机承载能力
分表无法降低单机连接压力(所有分表共享同一实例连接池),只有分库才能分散连接负载
指标阈值说明
活跃连接数(Threads_running)> CPU 核心数 × 2导致上下文切换频繁,CPU 效率下降
最大连接数使用率Max_used_connections / max_connections > 85%频繁出现 “Too many connections” 错误
QPS/TPS持续 > 10,000单 MySQL 实例难以稳定支撑
业务模块需强隔离(多租户/微服务)
业务需求分库价值
多租户 SaaS 系统每个客户独立库,保障数据隔离与安全(如钉钉、企业微信)
微服务架构用户服务、订单服务、商品服务各自独立数据库,避免耦合
合规要求金融/医疗等场景要求敏感数据物理隔离(如 GDPR)
读写分离无法满足读扩展需求
传统读写分离只能扩展读能力,而分库可同时扩展读+写能力
问题分库方案
主库写压力大 + 从库读延迟高按业务拆分多个主库(如用户库、订单库),每个库可独立做读写分离
热点数据集中(如秒杀商品)将热点表单独分库,避免影响其他业务

3.3 分库 vs 分表:决策树

image.png

归档vs分库

对比项归档分库
触发条件- 单表数据量过大(>500万行) - 历史数据占比 >70%- 单机CPU/IO/连接数饱和 - 多业务强耦合
数据流向单向迁移: 主库 → 归档库(如OSS/Hive)并行写入: 应用同时写多个库
查询方式- 热数据:查主库 - 冷数据:查归档库(需特殊入口)- 所有数据:通过中间件自动路由
事务要求无需分布式事务 (归档过程可异步)必须分布式事务 (保证多库数据一致)
典型工具- pt-archiver - 自定义脚本 - MySQL Event- ShardingSphere - MyCat - Vitess
运维成本低(仅需管理归档策略)极高(多实例监控/备份/扩容)
回滚难度高(冷数据恢复慢)中(需协调多库状态)

参考:www.51cto.com/article/800…