关于mysql为什么要分表的一些思路

文章一:

问题描述

  • 为什么进行分表? 分库?

  • 一般多少数据量开始分表?

  • 什么是数据库垂直拆分和水平拆分

回答

为什么要进行分库

业务发展,当单个数据库中的表越来越多,数据量越来越大的时候。数据的增删改查所消耗的资源就会增加。由于mysql是无法分布式部署(可能会有人说不是有主从吗?并不是,详细会在其他文章说明)的。==而单台服务器的资源,如CPU、磁盘、内存、IO等都是有限的。最终数据库所承载的数据量和处理数据的能力就会遇到瓶颈==。此时有两种解决方案:

  • 横向扩展

  • 纵向扩展

纵向扩展就是增加单台服务器的性能,如升级cpu,内存,磁盘换ssd等,这是最简单的方案,但是也是最烧钱的。

横向扩展就是对数据进行拆分,放置到多台服务器(相对廉价的服务器)上。对数据进行拆分,一般是对数据进行合理的分库,再对分离出来的库进行调优。即将单台服务器上的压力分布到多台机器中。这就是分库的理由

为什么进行分表

当MySQL的单表的数据达到一定量级的时候(如一千万)的时候,就需要考虑进行分表。因为此时的MySQL的执行性能就会下降(这和mysql本身的实现机制有关)。简单来讲有如下两个原因

  • 锁机制

为了保证数据的完整性,数据库有锁定机制。MySQL中有表锁定和行锁定,MySQL中myisam存储引擎是表锁定,innodb存储引擎是行锁定。分为包含共享锁和独占锁两种。独占锁就是整个数据文件归一个线程所有,其他线程就必须等待。==如果数据太多,一次执行的时间太长==,特别是在锁表的情况下,就会导致大量的其他SQL等待执行,严重影响系统的正常使用。

  • 索引更新

更新表数据时会导致索引更新,当单表数据量很大时这个过程比较耗时,这就是为什么对大表进行新增操作会比较慢的原因。并且更新表数据会进行表级锁或者行锁,这样就导致其他操作等待。

所以我们将大表拆分为多个字表,那么在更新或者查询数据的时候,压力会分散到不同的表上。由于分表之后每个表的数据较小,不管是查询还是更新都极大的提高了速度,即使出现最坏的“锁表”的情况,那其他表还是可以并行使用。

一般多少数据量开始分表

这个问题没有一个固定的答案,需要根据表的用途和业务来要求来评估此数据量。但是,当mysql的数据量达到千万级别的时候,就需要考虑是否需要进行分表操作。以下几个是一些参考因素:

  • 写入量(高峰期写入量,是否会造成锁表导致读或者写出现一些问题,insert,update,delete的比例各多少)

  • 查询量(查询量多大,是否跟写会造成相互影响)

  • 查询方式(单记录查询,还是多记录查询,是否有count查询,比重各占多少,每次返回的记录数数量级1,10,100,1000 。。。)

  • 是否有分页(重点关注,是否存在大分页)

1,2 算是比较基础的,正常1kw以下都没太大问题。3,4 受单表数据量的影响起始更小,但是反过来,这个就直接影响到 1,2

不同的情形,数据量的规模不太一样。例如,单表只有insert和单条查询的,每天增长百万数据,这种亿的规模问题都不大,当然能拆最好~

有简单 in 查询的,这种也能够接受~ 但是如果有比较大的查询,或者比较复杂的,包括大分页,然后还有大量的 update的,这种表就不能太大,正常不要超过 300w~

==update 的频率,应该算是里面影响比较大的因素==,insert一般只添加数据,不会对查询造成太多影响但是update和 select 可能就会有比较大的相互影响了~

什么是垂直拆分和水平拆分

  • 垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表 或者 将表按模块划分到不同数据库表中(分库或者拆表)

  • 水平拆分是指数据表行的拆分,比如表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放==(分表)==。



作者:姚小强
链接:https://www.jianshu.com/p/1b1576fc5917
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

文章二:

Mysql 分库分表思路

  • 2019年 09月23日
  • 83 阅读

随着业务的不断扩张,数据库的数据也在不断增加,大数据量下的查询和修改操作都会变得比较耗时,即使优化SQL和索引,也难以进一步提升性能,所以有必要考虑一下数据库的分库分表(Sharding),将数据库拆分成多个小数据集以提升效率。这里整理记录一下数据库分库和分表的一些思路和方法,以便今后实施。

为什么要使用分库和分表

主要原因是为了通过合理的数据库架构来存储不断增长的数据,同时要最大限度地提高数据库操作的效率。单个数据库的负载能力是有限的,数据量的不断增长可能会出现性能瓶颈,从业务层上看,就是查询时间过长,数据库连接无法及时释放,时间一长可能整个连接池都被占满了,后面的请求又拿不到数据库连接,这样的情况会恶性循环。为了解决这种情况,我们可以切分数据库,将数据切分成多个小数据集,以达到分散单个数据库负载的效果。

什么情况下使用分库和分表

在数据库优化的过程中,如果是查询请求增加,做主从分离,如果写入请求增加,做分库分表。总的来说,分库分表是为了解决数据库存储大量数据时出现的性能瓶颈。
数据库的性能瓶颈可分为IO瓶颈和CPU瓶颈。

  1. IO瓶颈
  • 磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的IO,降低查询速度 -> 分库和垂直分表。
  • 网络IO瓶颈,请求的数据太多,网络带宽不够 -> 分库。
  1. CPU瓶颈
  • SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> SQL优化,建立合适的索引。
  • 单表数据量太大,查询时扫描的行太多,SQL执行效率低,CPU率先出现瓶颈 -> 水平分表。

除了性能问题,我们进行服务化(SOA)的改造时,除了业务上需要进行拆分,底层的存储也需要进行隔离,这时可以用到垂直拆分数据库或表。

如何进行分库和分表

分库分表的方式有垂直切分和水平切分两种。以一个表格为例,垂直切分就是将部分列切分出去,数据结构被改变了,而水平切分就是将部分行切分出去,切分出去的数据结构与原来一样。
分库分表的顺序应该是先垂直分,后水平分。因为垂直分更简单,我们只要根据不同业务查询不同数据库或表,不用在额外查询数据的位置,更符合我们处理现实世界问题的方式。

垂直切分

  1. 垂直分表 可以用列表页和详情页来帮助理解。垂直分表的拆分是基于列字段进行的,原则是将热点数据(可能会冗余经常一起查询的数据)放在一起作为主表,非热点数据(数据较大,长度较长如text类型字段)放在一起作为扩展表。这样更多的热点数据就能被缓存下来,进而减少了随机读IO。拆分之后,要想获得全部数据就需要关联两个表来取数据。但记住,千万别用join,因为join不仅会增加CPU负担并且会讲两个表耦合在一起(必须在一个数据库实例上)。关联数据,应该在业务Service层做文章,分别获取主表和扩展表数据然后用关联字段关联得到全部数据。

  2. 垂直分库

对于数据库来讲,垂直切分就是将部分表分到其他数据库,垂直分库针对的是一个系统中的不同业务进行拆分,比如用户User一个库,商品Producet一个库,订单Order一个库。切分后,一般要放在多个服务器上,而不是一个服务器上。防止数据库的单库处理能力成为瓶颈。

水平切分

  1. 水平分表 针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。不建议采用。
  2. 水平分库 将单张表的数据切分到多个数据库服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。一般水平分库后,多个数据库是部署到不同服务器上,这样能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。
  3. 切分规则
    • RANGE:从0到10000一个表,10001到20000一个表;
    • HASH取模:一个商场系统,一般都是将用户,订单作为主表,然后将和它们相关的作为附表,这样不会造成跨库事务之类的问题。取用户id,然后hash取模,分配到不同的数据库上。
    • 地理区域:比如按照华东,华南,华北这样来区分业务,七牛云应该就是如此。
    • 时间:按照时间切分,就是将6个月前,甚至一年前的数据切出去放到另外的一张表,因为随着时间流逝,这些表的数据被查询的概率变小,所以没必要和“热数据”放在一起,这个也是“冷热数据分离”。

分库分表方案产品

借助中间件,使得分库分表对业务透明,目前市面上的分库分表中间件相对较多,其中基于代理方式的有MySQL Proxy和Amoeba, 基于Hibernate框架的是Hibernate Shards,基于jdbc的有当当sharding-jdbc, 基于mybatis的类似maven插件式的有蘑菇街的蘑菇街TSharding, 通过重写spring的ibatis template类的Cobar Client。

分库分表后面临的问题

跨库join

需要做两次查询,把两次查询的结果在应用层做合并。这种做法是最简单的,在应用层设计的时候需要考虑。

分库分表后表之间的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表,结果原本一次查询能够完成的业务,可能需要多次查询才能完成。
解决方法:

  1. 全局表:基础数据比如配置表,所有库都拷贝一份。
  2. 系统层组装:分别查询出所有数据,然后组装起来,可以把订单号字段同时放在订单表和订单详情表,这样可以同时发起查询。

分布式id

在分库分表后,我们不能再使用mysql的自增主键。因为在插入记录的时候,不同的库生成的记录的自增id可能会出现冲突。
因此,需要一个全局的id生成器,目前分布式id有很多种方案,其中一个比较轻量级的方案是twitter的snowflake算法。 其核心思想是:使用 41bit 作为毫秒数,10bit 作为机器的 ID(5 个 bit 是数据中心,5 个 bit 的机器 ID),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是 0。

事务支持

分库分表后,就成了分布式事务了,需要考虑补偿事务或者用 TCC(Try Confirm Cancel)协助完成。

来自:http://bins.top/tech/2019/09/23/mysql-sharding-thinking.html

猜你喜欢

转载自blog.csdn.net/jayxujia123/article/details/108174825