数据库分库分表入门

前言:想搞一下读写分离,看到读写分离经常和分库分表一起出现,所以一起来探究下分库分表到底是什么与其使用场景,有点复杂搞得我也有点晕,一些优点缺点都是复制的,还有其它一些,可能有点不准确,凑合看理解意思吧,供本人复习之用

参考:

https://www.jianshu.com/p/658bc9151e7b

https://blog.csdn.net/weixin_44062339/article/details/100491744

https://blog.csdn.net/vipshop_fin_dev/article/details/81416725

目录

第一章 分库分表概念

1.1 垂直分库

1.2 垂直分表

1.3 水平分库

1.4 水平分表

第二章 分库分表时的策略

2.1 垂直分库策略

2.2 垂直分表策略

2.3 水平分库分表策略

2.3.1 连续分片

2.3.2 随便分片

2.3.3. ID问题

第三章 应用问题

3.1 水平分表分页排序问题

3.2 垂直分库的事务问题


第一章 分库分表概念

1.1 垂直分库

将一个数据库中的一些关系紧密的表拆出来组成新的数据库

优点:

  • 业务系统解耦。
  • 与微服务治理类似,便于集中管理,监控,扩展
  • 高并发情况下提升IO,数据库连接数,单机硬件资源瓶颈

缺点:

  • 多表join只能通过应用程序解决,加大开发复杂度
  • 分布式事务处理复杂
  • 单表数据总量无法解决

数据库分库分表入门

 

1.2 垂直分表

如果有的表字段比较多,有的字段不常用或者字段长度较大,可以将这些字段拆分到扩展表中,mysql是按照数据页进行存储的,如果单行数据过大,会导致数据跨页,造成额外的性能开销。

适用情况: 

优点:

为了避免IO争抢并减少锁表的几率

充分发挥热门数据的操作效率

解释:为什么大字段IO效率低:第一是由于数据量本身大,需要更长的读取时间;第二是跨页,页是数据库存储单位,很多查找及定位操作都是以页为单位,单页内的数据行越多数据库整体性能越好,而大字段占用空间大,单页内存储行数少,因此IO效率较低。第三,数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。

数据库分库分表入门

1.3 水平分库

数据库中某表的数据特别多,有几千万数据,所以对此表进行一些操作的话会很慢,这时需要水平分库。水平分库就是把库中表里的数据按某一规则进行进行拆分,最后拆分到两个库里。

适用情况:

优点:

  • 解决了单库大数据,高并发的性能瓶颈。
  • 提高了系统的稳定性及可用性。
  • 切分后表结构相同,程序改动小

缺点:

  • 同一个表被分配在不同的数据库,需要额外进行数据操作的路由工作,因此大大提升了系统复杂度。
  • 数据扩容
  • 分片规则难以抽象(不同的库,难以固定某个字段拆分,比如商品可以商品IDhash到某个库中,订单表需要根据用户IDhash到某个库中)
  • 分布式事务,部分业务无法关联join

数据库分库分表入门

 

1.4 水平分表

水平分表也是为了解决表的数据量过大的问题,但是它把表拆成两个后依旧放在一个数据库中。

优点:

  • 优化单一表数据量过大而产生的性能问题

  • 避免IO争抢并减少锁表的几率

缺点:

  • 操作复杂度提升(分页啥的)

写在最后:感觉水平分库和水平分表差不多,是不是可以分在一个类别里面呢?

 

第二章 分库分表时的策略

2.1 垂直分库策略

感觉就是业务相近的表分在一个库里面吧,如商品库,订单库

2.2 垂直分表策略

将访问频次低的,占用空间较大的放在一个单独表里,访问频次高的放在一张表里。或者经常组合查询的列放在一张表里。

2.3 水平分库分表策略

感觉这两种策略一样就拉一起来说了,水平划分通常是先确定主表,将主表与其关联表和间接关联表划分到同一个sharding。如确定答题卡表为主表,那么与其关联的答案表也一起划分到同一个sharding(个人感觉意思应该是我们以答题卡上有很多答案,我们先对答题卡进行分片,然后要对答案进行分片时直接参考答题卡的分片就行了,即答题卡在哪片,对象的答案就在哪片)。

2.3.1 连续分片

连续分片,比如确定userId为关键字,userId在(0,10000000]在shard_0,userId在(10000000,20000000]在shard_1。

优点:扩容方面,连续分片更加容易扩容,当关键字增长到达某一个段的时候,添加新的分片即可,不需要进行数据迁移。

缺点:存在数据热度不一致的问题,比如1年前的微博数据和现在的微博数据热度差异巨大,连续分片的情况下会导致各个库的访问压力不均匀。

对于随机分片的数据迁移问题,也有一些优化的策略。比如采用一致性哈希算法进行分片,那么每次扩容的时候,所要迁移的数据量则会大大减少。

2.3.2 随便分片

通过对关键字进行hash取模进行分片,例如确定userId为关键字,划分成32个分片,则index=userId%32。

优点:数据热度通常更加均匀。

缺点:在进行扩容的时候需要进行数据迁移。

2.3.3. ID问题

一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由。

我在这只简要说明下UUID和雪花生成策略,更详细的可以看这个:https://blog.csdn.net/qq_41428035/article/details/103165055

UUID:就是根据MAC,纳米级时间、芯片ID等等生成个不重复的长度36位的字符串,

雪花:根据时间、数据中心编号、机器编号等生成一个有序的长整型id

优缺点:
 

数据库分库分表入门

 

第三章 应用问题

3.1 水平分表分页排序问题

如果要分页排序的数据都在一个分片(数据库)上,那么跟单个数据源的没什么关系。

如果要对所有的数据进行分页排序,那要从各个分片上查出数据,然后汇总排序,分页的难度会随着页码的增加而增加。例如查询第一页的数据,只需要在各个分片上查询出第一页的数据,然后再汇总排序,但如果查询第20页的数据,就需要把各个分片的前20页的数据都查询出来(因为无法确保前20页的数据到底在哪,万一前20页的数据都在某一片呢),然后再汇总进行分页排序,这个数据量就非常大,性能也会急速下降。

解决跨分片的分页排序难题更多的是在产品设计上进行优化,比如尽量规避这种跨分片分页排序的需求;只允许用户查看前面几页;尽量缩小查询范围。

而技术角度的解决,通常是通过一些冗余数据来进行,可以冗余一张表,里面存与分页相关的数据,先根据表把分页数据的关键字找出来,再根据关键字去找数据。

具体例子:比如上述按照时间分页排序的需求如果很强烈的话,可以冗余一张时间和答案ID的映射关系表,先在这个表里查询出最终显示的答案ID,然后再根据这些答案ID去查询答案数据。或者通过大数据平台,把所有数据汇总起来解决。

3.2 垂直分库的事务问题

之前在一个数据库里可以直接通过数据库自带的事务解决,当分到不同的数据库里就不行了,需要使用分布式事务,具体可以参考:https://blog.csdn.net/q610376681/article/details/109090927