「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
为什么要分库分表
随着业务运营时间的推移,表结构可能变得不合理、表变多、单表数据量在变大、总数据量在变大、并发访问量可能在变大等等。将会带来以下问题:
-
表结构不合理:字段类型/长度定义不合理、表不符合范式、存在多个大字段、索引定义不合理等等会使表变得臃肿,CRUD会变慢。
-
表变多:相对而言数据量会线性变大,数据量变大意味着需要访问的数据在变多,所以对于单机而言资源(cpu、io、内存、带宽等等)扩容有限,CRUD会变慢。
-
单表数据量在变大:如果只是单表数据量在变大,相对而言只会影响本表的CRUD。
-
总数据量在变大、并发访问量变大:对整个数据库服务器的资源的压力会变大。
- 对于第一点,需要考虑重新设计表可能会涉及对表的垂直拆分。
- 对于第二点,可以针对读写进行读写分离分为读库和写库避免所有操作都在一个库中完成从而削减单库压力,可以理解为对库的水平划分,如果读写分离也无法解决,就使用分布式数据库解决。
- 对于第三点,单纯单表数据量变大不是因为表结构不合理那只能是对表进行水平拆分,可以对表进行分区,分区可以逐渐演变,开始可以在单机分区,最后因为单机资源的限制只能使用分布式数据库。
- 对于第四点就是第二点和第三点的组合了,这里不再赘述。
以上问题都出现,可以结合使用分库和分表。
分库分表的策略
上面其实大概都有提到,这里我们详细描述下。
垂直分
垂直拆分可以是表和库。
表
表进行垂直拆分主要有两个方向:冷热、大字段。
冷热: 比如用户表的字段有姓名、身份证、头像、注册时间、状态、邮箱、手机号、职业等,但是平时只需要头像、用户名、状态,当用户进入基本信息的时候还需要其他信息,那么当用户量比较大时为了提升CRUD的速度我们可以分为用户表(姓名、头像、注册时间、状态、手机号)和用户基本信息表(身份证、邮箱、职业等)。这样的好处显而易见。行数据字段变少占用的空间就变小。数据库以数据页为单位加载到内存,这样能加载行就更多,命中率更高,减少磁盘IO从而提高数据库性能。
大字段: 大字段更容易拆分,比如文章表的字段有发表人id、发表时间、最近修改时间、标题、简介、内容等。内容就属于大字段,我们可以把内容字段单独拆到另一张表中,需要的时候我们再关联查询。好处和冷热拆分的优点一样。
库
库进行拆分就是把表拆分到不同的库中,通常根据业务按照模块划分。比如一个下单流程,大概设计到商品、用户、订单。我们就可按照模块分为:商品库(可以包括类别表、商品表、商品规格表等和商品相关的表)、用户库(可以包括用户表、用户基本信息表、用户认证表、账户表等和用户相关的表)、订单库(订单总表、订单明细表、支付记录表、发货表等和订单相关的表)。
优点
- 垂直表拆分可以提高CRUD的速度。
- 垂直库拆分可以把不模块拆到不同库中摆脱单机对性能的约束。同时业务代码也更加解耦、表之间的关系也强制更加清晰、业务扩展也更加方便。
缺点
- 垂直拆分会带来关联查询的问题,特别是不同模块需要关联。
- 单库事务升级为分布式事务,实现难度加大。
- 单表数据量在变大还没有解决。
水平分
水平拆分可以用于解决单表数据量变大和读写分离,所以也为库水平拆分和表水平拆分。
库
即读写分离,库被水平拆分,可以把读性能和写性能的消耗分到两台机器上提升性能。例如常见的管理后台的统计报表涉及表多、数据行多就可以走读库避免对用户端的性能影响。
表
即把单表进行水平拆分,可以先在单机上进行分区,再分到不同库中。水平拆分可以分为:范围分区、列表分区(和范围的区别是可以不连续)、列分区(可以个多列一起决定分区)、hash分区(需要注意要均匀分布)、子分区。(有空再出一篇文章)最常用的范围、列表、hash分区,比如根据时间、区域、服、手机号hash、uuid hash等。
优点
- 读写分离,库被水平拆分,可以把读性能和写性能的消耗分到两台机器上提升性能。
- 解决单表数据量变大带来的性能问题。
缺点
- 关联查询的问题。
- 读写同步问题。
- 均匀分布问题。
- 修改触发分区变更问题。
- 分布式全局唯一id问题
后续
分库分表可以解决一些问题,但是也会带来一些其他问题,针对上述分库分表的缺点笔者将带来后续文章。
分库分表问题汇总
- 读写同步问题 《Mysql之主备同步》
- 分布式关联查询问题
- 分布式事务问题
- 表分区均匀分布问题
- 修改触发分区变更问题
- 分布式全局唯一id问题 《Mysql分库分表相关问题之分布式全局唯一id》