分库分表是解决数据库单点性能瓶颈的常见架构手段。本文将结合订单业务场景,系统性地解析垂直分库、垂直分表、水平分库、水平分表四种核心拆分方式,并探讨路由算法、技术难点与主流中间件选型,为实际落地提供清晰指引。
什么是分库分表
分库 和 分表 本质上是两个独立的概念,但由于在实践中两者经常协同使用,久而久之便被合称为“分库分表”。
其核心目标在于解决单一数据库或数据表因数据量过大而导致的性能持续下降问题。通过既定规则,将庞大的数据库拆解为多个独立的库,将庞大的数据表拆解为若干张小表,从而使每个库、表都能达到性能最优(响应速度最快),进而提升整体数据库的处理能力。
如何分库分表
分库分表的核心理念在于对数据进行切分(Sharding),以及切分后如何快速定位数据并整合查询结果。无论是分库还是分表,都可以从 垂直(纵向)和 水平(横向)两个维度进行。

下面我们以订单业务为例,具体看看库和表的垂直与水平切分如何操作。
垂直切分
垂直切分包含 垂直分库 和 垂直分表。
1、垂直分库
垂直分库的理解相对直观,其核心理念就是四个字:专库专用。
依据业务类型对数据表进行分类,例如将订单、支付、优惠券、积分等相关的表分别放入对应的独立数据库中。开发人员不能直接跨库访问其他业务的数据,如需获取,应由对应业务方提供 API 接口,这实际上构成了微服务架构的雏形。
垂直分库很大程度上依赖于业务的清晰划分。但现实中业务边界并非总是泾渭分明,例如拆分订单数据时,就需要考虑它与其他业务(如用户、商品)的关联,并非简单地将订单表堆到一个库里即可。
虽然垂直分库在一定程度上提升了数据库的处理能力,但它并未从根本上解决单表数据量过大引发的性能问题,因此通常需要配合水平切分来共同应对。

2、垂直分表
垂直分表 则是以数据表的列(字段)为依据进行切分,属于一种“大表拆小表”的模式。
例如,一张 order 订单表,可以将订单编号、金额等访问频繁的字段单独拆成一张核心表;而将 BLOB 类型的大字段或访问频率较低的字段(如订单备注详情),拆分出来创建一张扩展表 order_extend。这样,每张表只存储原表的一部分字段,这些拆分后的表还可以进一步分散到不同的数据库中。

数据库加载数据到内存时,是以行为单位的。经过垂直分表后,核心表通常只包含访问频次高、长度较短的字段,从而能在内存中加载更多数据行,提高查询的缓存命中率,减少磁盘 I/O,最终达到提升数据库性能的目的。
垂直切分的优点:
- 业务间数据解耦,不同业务的数据可以独立进行维护、监控和扩展。
- 在高并发场景下,能在一定程度上缓解数据库的读写压力。
垂直切分的缺点:
- 增加了系统开发的复杂度。由于业务数据被隔离,很多关联查询无法直接进行,必须通过调用接口或服务来聚合数据。
- 分布式事务的管理难度增大。
- 并未根治单表数据量过大的问题,需要与水平切分结合使用。
水平切分
如前所述,垂直切分后,单库单表的数据量可能依然庞大。当应用无法通过更细粒度的垂直拆分来提升性能时,如果仍存在单库读写和存储的性能瓶颈,就需要引入水平切分。水平切分能显著提升数据库的扩展性和处理能力。
1、水平分库
水平分库是指将同一个表按照一定规则拆分到不同的数据库中,每个库可以部署在不同的服务器上,从而实现水平扩展,这是一种非常有效的提升数据库性能的方式。
这种方案能够有效解决单库存储容量和性能的瓶颈。但由于同一张表的数据被分布到了多个数据库,任何数据访问都需要额外的路由计算,因此系统的复杂度也随之增加。
例如下图中,订单DB_1、订单DB_2、订单DB_3 三个数据库内部都有结构完全相同的 order 表。当访问某笔订单时,可以通过对订单编号取模的方式(例如 订单编号 mod 3,其中3是数据库实例数量)来确定该订单数据位于哪个数据库,进而进行操作。

2、水平分表
水平分表是在 同一个数据库实例内部,将一张大数据量的表按照一定规则,切分成多个表结构完全相同的子表,每个子表只存储原表的一部分数据。
例如:一张 order 订单表有900万条数据,经过水平拆分为三张表:order_1、order_2、order_3,每张表存储大约300万条数据。

单纯的水平分表虽然拆分了表,但所有子表仍然位于同一个数据库实例中。它只解决了单一表数据量过大的问题,并没有将负载分散到不同的物理机器上,子表们仍在竞争同一台服务器的CPU、内存、网络IO等资源。要想进一步获得性能提升,就必须将拆分后的表分散到不同的数据库(即进行水平分库),以达到真正的分布式效果。

水平切分的优点:
- 解决高并发场景下单库/单表数据量过大的问题,显著提升系统的稳定性和负载能力。
- 对业务系统的代码改造工作量相对可控。
水平切分的缺点:
- 跨分片的事务一致性难以保证。
- 跨库的 JOIN 关联查询性能较差,甚至无法直接进行。
- 后期数据扩容的难度和维护量较大(想象一下数据表被拆分成几千张子表的管理复杂度)。
“一定规则”是什么?
上文多次提到的 一定规则,本质上是一种数据路由算法,它决定了一条数据具体应该存储在哪个数据库的哪张表里。
常见的路由算法有 取模算法 和 范围限定算法。
1、取模算法
按照某个关键字段取模(对字段的哈希值或直接对字段值进行取余运算,即 hash(field) mod N,其中 N 为数据库实例数或子表数量),这是最常用的分片方式之一。
仍以 order 订单表为例。先对数据库从 0 到 N-1 进行编号,对订单表中的 order_no(订单编号)字段进行取模运算,得到余数 i。若 i=0 则存入第一个库,i=1 存入第二个库,以此类推。
这样,同一笔订单的所有相关数据都会落在同一个库和表中。查询时,使用相同的规则对 order_no 进行计算,就能快速定位到数据所在位置。
优点:
- 数据分片相对均匀,不容易出现所有请求都打到同一个数据库上的“热点”问题。
缺点:
- 扩容和缩容比较麻烦。例如,当某一台数据库服务器宕机并从集群中移除时,N 变为 N-1,原有的取模规则会发生改变,导致大部分数据无法被正确路由到,需要迁移大量数据。
2、范围限定算法
按照 时间区间 或 ID区间 等范围进行切分。例如,按用户ID切分:定义每个库的 user 表只存储10000个用户,第一个库存用户ID 1~9999,第二个库存10000~19999,第三个库存20000~29999,以此类推。按时间范围划分也是同理。
优点:
- 单表数据量是可控的。
- 水平扩展简单,只需增加新的分片节点即可,无需对现有分片的数据进行迁移。
- 能快速定位要查询的数据在哪一个分片。
缺点:
- 容易产生数据热点。例如按日期分片,如果遇到“双十一”等活动,某几天的订单数据会急剧增长,导致对应的分片被频繁读写,压力巨大;而存储历史数据的分片则可能很少被访问。
分库分表的难点
1、分布式事务
由于数据表分布在不同数据库中,跨库事务问题不可避免。虽然可以使用“两阶段提交(2PC)”、“三阶段提交(3PC)”等强一致性方案,但这类方案性能较差,且代码实现复杂。实践中更常用的是最终一致性方案,例如通过事务补偿(如TCC)、可靠消息队列等,在系统可接受的时间窗口内达到数据一致。
2、分页、排序、跨库联合查询
分页、排序、多表联合查询在单体数据库中是普通操作,但在分库分表后变得异常复杂。它需要从所有相关分片中查询出部分数据,在内存或中间件层进行汇聚、排序、合并后,再返回给用户,效率和处理逻辑都面临挑战。
3、分布式主键
分库分表后,单个数据库实例上的自增主键已无法保证全局唯一。此时,需要一个能够生成全局唯一ID的系统,即 分布式ID 生成服务(如Snowflake算法、UUID、号段模式等)。
4、读写分离
主流关系型数据库普遍提供主从复制的高可用方案。在实际架构中,我们往往需要实现 读写分离 与 分库分表 的结合,即写库和读库集群都需要进行分库分表处理,这对中间件的能力提出了更高要求。
5、数据脱敏
数据脱敏是指对身份证号、手机号、银行卡号、密码等敏感信息,通过特定规则进行转换,以实现隐私数据的可靠保护。在数据被分散存储和访问后,确保脱敏策略的一致性也是一个需要考虑的问题。
分库分表工具
建议优先考虑成熟的业界方案,将精力聚焦于业务实现。以下是一些主流的分库分表中间件:
ShardingSphere(前身 sharding-jdbc,Apache基金会)
MyCAT
Vitess(谷歌)
TSharding(蘑菇街)
Atlas(奇虎360)
Cobar(阿里巴巴,已停止维护)
Oceanus(58同城)
为什么选 ShardingSphere(sharding-jdbc)
在众多 Java 技术栈的选型中,ShardingSphere 是一款非常流行的轻量级 Java 框架。它最初以 sharding-jdbc 的名称被熟知,以 JAR 包形式提供服务,属于 客户端模式 的数据库中间件。这意味着它无需独立部署,可以理解为是一个增强了分片等功能的 JDBC 驱动。
相比之下,像 MyCAT 这类属于 服务端模式 的代理,需要单独的部署和运维,架构稍显复杂。对于希望简化运维、更专注于业务开发的团队而言,客户端模式的产品侵入性更小,上手更快。
此外,ShardingSphere 的兼容性非常出色:
- 它适用于任何基于
JDBC 的 ORM 框架,如 JPA、Hibernate、MyBatis、Spring JDBC Template 或直接使用原生 JDBC。
- 完美兼容各种第三方数据库连接池,如
DBCP、C3P0、Druid、HikariCP 等。
- 支持几乎所有主流的关系型数据库,如
MySQL、PostgreSQL、Oracle 等。
它对于项目的侵入性很小,通常无需修改业务代码和 SQL 语句,主要通过配置来定义分库分表规则,极大地降低了接入成本。
总结
本文回顾了分库分表的基本概念、拆分方式、路由算法以及面临的挑战。在 云栈社区 的 数据库与中间件 板块,你可以找到更多关于 MySQL、Redis 等数据库的深度讨论。理解了这些基础原理后,下一步便是结合具体框架(如 ShardingSphere)进行实战配置与开发,后续文章将对此展开详细探讨。