mysql 分库分表
上一篇文章我们介绍了mysql的主从读写分离,这里我们介绍分库分表的应用。
什么是分库分表呢,分就是拆分,也就是将一个数据表(库)拆分成多个。那有什么作用呢,可以分散流量,和主从类似,主从是将读写流量分开,方便扩展,这里是将表(库)分开方便扩展。同时流量分散,比如一张上亿数据的表,那么查询起来肯定很慢,但是要是水平拆分成多张表,每张表的数据量就会很小,查询速度就会变快。
分库分表一般分为两种,一种是水平拆分,一种是垂直拆分。
垂直拆分
垂直拆分,比如你现在所有的表都放在一个库中,那么这个库会很庞大,那我们可以按照业务来拆分成多个数据库,比如用户相关的用户库,交易相关的交易库等等。
这种拆分理念和微服务的理念差不多,微服务同样是按照业务来划分。
这样处理用户相关的只会访问用户库,不会对其他数据库造成压力,同样的,我们用户库有压力也方便单独扩展。
表的垂直拆分同样的道理,不过一般在表设计的时候就已经拆分好了,不应该出现一张表还能进行拆分的情况。
水平拆分
水平拆分,比如你现在表数据量过大,一张表拥有上亿的数据量,这时候就要把一张表拆分成多张表。
怎么拆分呢,一般有两种方法,比如
取余法
假设我们现在将一张千万级的表拆分成100个表,每张表的数据大概在十万量级。那我们怎么确定一条数据应该存在哪张表中呢,我们可以对数据的id进行取余操作,也就是 id % 100 = 1那就存放在一号表中, 2就放在2号表,以此类推。也可以hash一下再取余,比如hash(id) % 100。
分段法
也就是我们确定区间,比如前十万用户存在一号表,然后十万十万的类推,或者根据时间,每个月的用户一张表都可以。
join问题
那现在有一个问题,比如查询用户的时候需要查询出用户的余额,以前我们是join的方式联查,那现在分成多个表之后就没法join了,我们只能先查询出用户信息,然后再查询出这个用户的余额
条件查询问题
经过分表之后,数据分布在不同的地方,我们如果是查询id是5的用户,很简单,5 % 100就可以知道在哪张表中了,但是我们要查询姓名是张三的用户怎么办呢。我们要去查询哪张表呢,这个时候我们就需要做一个映射了,比如有一张表存储id 和 姓名的映射,我们通过这张映射表查询到张三的id,在id % 100来确定查询哪张表。这张映射表同样要分表,那我们怎么确定张三在哪张映射表中呢,我们可以用hash(张三) % 100的方式确定在哪张映射表中。
主键唯一问题
还有一个问题,原来我们在一张表中,主键只要做到表唯一,我们现在100张表,怎么保证这条记录的主键id在这100张表中都是唯一的呢。
有一种方法,我们生成唯一的uuid就可以了,但是这样有几个问题
- 有序性
一般来说,我们都会使用自增id,保持id有序并且单调递增,为什么呢,因为mysql的innoDb引擎使用B+树存储索引数据,而主键就是一种索引。
索引数据在B+树种有序存储,这样不管是写入还是查询的效率都会很高,而如果是无序的,那么写入和查询的效率就会降低。
因为有序的时候可以使用很多搜索算法提高查询效率。
- 表达性
uuid不具备任何表达性,没办法看到从种看到这个uuid是属于哪个业务的。
知道了问题所在,我们就可以解决了。
在一下篇文章中会介绍snowFlake算法来解决这个问题。