
1. 分库分表的原理和实现
什么是分区、分表、分库 ?
分区
就是把一张表的数据分成 N 个区块,在逻辑上看最终只是一张表,但底层是由N 个物理区块组成的。
分表
就是把一张表按一定的规则分解成 N 个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表明,然后操作它。
分库
一旦分表,一个库中的表会越来越多。
2. 分库分表的几种常见形式
2.1 垂直分表 (大表拆小表)

拆分是基于关系型数据库中的 “列”(字段)进行的。通常情况,某个表中的字段比较多,可以新建立一张 “扩展表”,将不经常使用或者长度较大的字段拆分出去放到“扩展表”中。
拆分后会遇到很多问题(例如:跨库 join,分布式事务等)
2.2 垂直分库
基本的思路就是按照业务模块来划分出不同的数据库,而不是像早期一样将所有的数据表都放到同一个数据库中。

2.3 水平分表 (横向分表)

将表中不同的数据行按照一定规律分布到不同的数据库表中(这些表保存在同一个数据库中),这样来降低单表数据量,优化查询性能。最常见的方式就是通过主键或者时间等字段进行 Hash
和 取模(MOD)
后拆分。
注意
: 水平分表,能够降低单表的数据量,一定程度上可以缓解查询性能瓶颈。但本质上这些表还保存在同一个库中,所以库级别还是会有 IO 瓶颈。所以,一般不建议采用这种做法。
2.4 水平分库分表
水平分库分表与上面讲到的水平分表的思想相同,唯一不同的就是将这些拆分出来的表保存在不同的数据中。这也是很多大型互联网公司所选择的做法。

某种意义上来讲,有些系统中使用的 “冷热数据分离”(将一些使用较少的历史数据迁移到其他的数据库中。而在业务功能上,通常默认只提供热点数据的查询),也是类似的实践。在高并发和海量数据的场景下,分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破 IO、连接数、硬件资源的瓶颈。当然,投入的硬件成本也会更高。同时,这也会带来一些复杂的技术问题和挑战(例如:跨分片的复杂查询,跨分片事务等)
3. 分库分表的带来的技术难点
3.1 跨库 join, count, order by, group by及聚合函数
在拆分之前,系统中很多列表和详情页所需的数据是可以通过 sql join
来完成的。而拆分后,数据库可能是分布式在不同实例和不同的主机上,join
将变得非常麻烦。而且基于架构规范,性能,安全性等方面考虑,一般是禁止跨库 join
的。
如何解决:
- 优先调整垂直分库的设计问题
全局表:
就是有可能系统中所有模块都可能会依赖到的一些表。比较类似我们理解的 “数据字典”。为了避免跨库 join
查询,我们可以将这类表在其他每个数据库中均保存一份。同时,这类数据通常也很少发生修改(甚至几乎不会),所以也不用太担心“一致性”问题。
字段冗余:
这是一种典型的反范式设计,在互联网行业中比较常见,通常是为了性能来避免 join
查询。但是适用场景有限, 还需要维护冗余的字段。
数据同步:
定时 A 库中的 tab_a
表和 B 库中 tbl_b
有关联,可以定时将指定的表做同步。当然,同步本来会对数据库带来一定的影响,需要性能影响和数据时效性中取得一个平衡。这样来避免复杂的跨库查询。
系统层组装:
在系统层面,通过调用不同模块的组件或者服务,获取到数据并进行字段拼装。
3.2 跨库事务(分布式事务)的问题
深入理解PHP+Mysql分布式事务与解决方案 - 知乎
3.3 ID 问题
当我们进行分库分表的拆分之后,如果继续使用原来的表自增的方式显然最终查询出来的结果会出现 id
重复问题,处理分库分表下的 id
,一般有下面几种方法:
- UUID
缺点:
uuid 长度太长,占据的空间比较大,作为索引并且基于索引的查询性能上面会有一定的影响。
- 创建一个
sequence
表来维护表明和 id
的关系
CREATE TABLE `SEQUENCE` (
`table_name` varchar(18) NOT NULL,
`nextid` bigint(20) NOT NULL,
PRIMARY KEY (`table_name`)
) ENGINE=InnoDB
- 每当需要为某个表生成id时,就从 `sequence` 表当中取出 `next_id` ,并将 `next_id` 加一后存入表中,当然缺点也很明显:所有插入数据库当中的数据,都要访问这张表,这张表很容易成为系统瓶颈。
- Twitter 的分布式 id 算法
Snowflake
3.4 跨分片的分页排序
对于跨表之间的分页问题,当我们想要访问的是前几页数据时,可以对各个节点进行分页查询,然后再对结果集进行汇总处理,尤其需要注意,如果想要查询第 100 页的数据,这时候,不是单纯的去查询每个表当中第 100 页开始,10 条数据,然后进行汇总,而是需要把每个表当中从 0 开始到 100 页的数据全部查询出来,然后再此基础上进行汇总查询出来第 100 页的数据。
4. 常见的分库分表的工具
- sharding-sphere:jar,前身是 sharding-jdbc
- TDDL:jar,Taobao Distribute Data Layer
- Mycat:中间件