两种切分方式

水平切分

水平切分又称为 Sharding,它是将同一个表中的记录拆分到多个结构相同的表中。

当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。


垂直切分

垂直切分是将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。

在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。


Sharding 策略

  • 哈希取模:hash(key) % N;
  • 范围:可以是 ID 范围也可以是时间范围;
  • 映射表:使用单独的一个数据库来存储映射关系。

Sharding 存在的问题

1. 事务问题

使用分布式事务来解决,比如 XA 接口。

2. 连接

可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。

3. ID 唯一性

  • 使用全局唯一 ID(GUID)
  • 为每个分片指定一个 ID 范围
  • 分布式 ID 生成器 (如 Twitter 的 Snowflake 算法)

分库+分表

分库:一个数据库包括多张表,造成数据库过于庞大。把一个数据库拆成若干个数据库。分库的两种形式:水平分库和垂直分库。垂直分库就是把不同的表划分到不同的数据库;水平分库就是按照 region 进行分库,每个 region 都有自己的一套数据。
分表:一个表中存储的行数过多,造成单表过大。可以进行水平切分和垂直切分。垂直切分就是竖着切一刀,是把大表中的列分成若干组,每组是一个表。水平切分就是横着来一刀,是根据数据中的某一列进行切分(此列被称为 sharding column),其实就相当于把数据的某个键切分成了若干个区间。每个区间是一个表。

(1)单库太大:数据库里面的表太多,所在服务器磁盘空间装不下,IO 次数多 CPU 忙不过来。
(2)单表太大:一张表的字段太多,数据太多。查询起来困难。

分表中的水平切分是一个业务无关、纯技术性问题,常见的中间件有 MyCAT,ShardingSphere,ProxySQL 等。

分库分表产生的问题

  • 外键约束就不能用了
  • 联合查询困难,只能在代码层面实现联合查询。
  • 需要支持分布式事务。
  • 跨节点分页、排序问题。
  • 全局主键避免重复问题。不能依赖数据库的自增 id,可以自己实现自增 id 服务。

sharding column 与冗余存储

分库分表会使得查询变得非常复杂。例如考虑用户关系表,这个表有三个字段 id,from_user,to_user,表示 from_user 关注了 to_user。如果按照 from_user 进行分表,那么可以快速获取某个用户的关注列表,然而却无法获得用户的粉丝列表(需要枚举全部表并拼接起来,分表的意义大打折扣);如果按照 to_user 进行分表,能够获取用户的粉丝列表,却无法快速获得用户的关注列表。
那么如何解决这个问题呢?冗余存储。按照 from_user 分表一次,然后按照 to_user 分表一次。