分库和分表解决了什么问题?
把以前存在一个数据库实例里的数据拆分成多个数据库实例,部署在不同的服务器中,这是分库。
分库是为了解决服务器资源受单机限制,顶不住高并发访问的问题,把请求分配到多台服务器上,降低服务器压力。
把以前存在一张表里面的数据拆分成多张表,这是分表。
分表是为了解决由于单张表数据量多大,而导致查询慢的问题。
一般怎么分库?
一般分库都是按照业务划分的,比如订单库、用户库。
分库会带来哪些问题?
事务问题
关系型数据库,有很大一点在于它保证事务完整性,分库之后单机事务就用不上了,必须使用分布式事务来解决。-
连表JOIN 查询问题
在一个库中的时候我们还可以利用 JOIN 来连表查询,而跨库了之后就无法使用 JOIN 了。解决办法:- 就是在业务代码中进行关联,也就是先把一个表的数据查出来,然后通过得到的结果再去查另一张表,然后利用代码来关联得到最终的结果。
- 适当的冗余一些字段,避免JOIN操作
一般怎么分表
-
垂直分表
垂直分表的原理比较简单,一般就是把某几列拆成一个新表,这样单行数据就会变小,B+树里的单个数据页(固定16kb)内能放入的行数就会变多,从而使单表能放入更多的数据。这样内存存放更多有用的数据,就减少了磁盘的访问次数,性能就得到提升。
-
水平分表
分表算法可以分为:Hash 路由,范围路由,路由表
-
Hash 路由
其实就是选择表中的某一列,然后进行 Hash 运算,将 Hash 运算得到的结果再对子表数进行取模,这样就能均匀的将数据分到不同的子表上。- 优点是:
数据分布均匀 - 缺点是:
就是增加子表的时候麻烦,得重新映射数据
- 优点是:
范围路由
其实很简单,可以是时间,也可以是地址,表示一定的范围的即可。
比如本来一张 User 表,我可以分 User_HZ、User_BJ、User_SH,按照地名来划分 User。
比如 log 表,我可以将表分为 log_202103、 log_202104,把日志按照年月来划分。路由表
是专门搞个表来记录路由信息,一般不怎么用。
-
分表会带来哪些问题?
垂直分表还好,就是查询数据需要关联一下。
水平分表会带来很多问题:
- 排序、count、分页问题
如果一个用户的数据被拆分到多个表中,那查询结果分页就不像以前单张表那样直接就能查出来了,像 count 操作也是一样的。
- 全局主键的问题
以前单表的时候很简单,就是主键自增,现在分表了之后就有点尴尬了,所以需要一些手段来保证全局主键唯一。- 还是自增,只不过自增步长设置一下。比如现在有三张表,步长设置为3,三张表 ID 初始值分别是1、2、3。 这样第一张表的 ID 增长是 1、4、7。第二张表是2、5、8。第三张表是3、6、9,这样就不会重复了。
- UUID,这种最简单,但是不连续的主键插入会导致严重的页分裂,性能比较差。
- 分布式 ID,比较出名的就是 Twitter 开源的 sonwflake 雪花算法。