咱们为何要分库分表

本文转自:https://baijiahao.baidu.com/s?id=1627688882923429891&wfr=spider&for=pcmysql

 

当一张表的数据达到几千万时,查询一次所花的时间会变长。这时候,若是有联合查询的话,可能会卡死在那儿,甚至把系统给拖垮。算法

而分库分表的目的就在于此:减少数据库的负担,提升数据库的效率,缩短查询时间。另外,由于分库分表这种改造是可控的,底层仍是基于RDBMS,所以整个数据库的运维体系以及相关基础设施都是可重用的。sql

目前咱们系统将近20亿数据,每张表最大的接近600w条/表,每条数据大约3k,每一个表将近1.5G的数据。查询常常超时,单条SQL执行count(*)查询时间达到了最大260ms,0.26s(标准是超过0.1s的数据为慢SQL)。数据库

为了说明咱们为何要分库分表,咱们看一下sql的执行过程。服务器

mysql执行一条sql的过程以下:运维

一、收到sql数据库设计

二、把sql放到排队队列中分布式

三、执行sqlide

四、返回结果性能

在这个执行过程当中最花时间的地方在于:

1.排队等待的时间,

2.sql的执行时间。

若是有2个sql都要同时修改同一张表的同一条数据,mysql对这种状况的处理是:一种是表锁定(MyISAM存储引擎),一个是行锁定(InnoDB存储引擎)。

表锁定表示其余操做都不能对这张表进行操做,必须等当前对表的操做完才行。行锁定也同样,别的sql必须等这条数据操做完了,其余人才能对这条数据进行操做。

若是数据太多,一次执行的时间太长,等待的时间就越长,这也是咱们为何要分表的缘由。

 

分库分表术语:

读写分离: 不一样的数据库,同步相同的数据,分别只负责数据的读和写;

分区:指定分区列表达式,把记录拆分到不一样的区域中(必须是同一服务器,能够是不一样硬盘),应用看来仍是同一张表,没有变化;

分库:一个系统的多张数据表,存储到多个数据库实例中;

分表: 对于一张多行(记录)多列(字段)的二维数据表,又分两种情形:

垂直分表: 竖向切分,不一样分表存储不一样的字段,能够把不经常使用或者大容量、或者不一样业务的字段拆分出去;水平分表(最复杂): 横向切分,按照特定分片算法,不一样分表存储不一样的记录。在实际生产中,一般的进化过程是:单库单表->单库多表->多库多表;;分区->分表->分库(垂直分库 - 水平分库 - 读写分离)

单库单表

单库单表是最多见的数据库设计,例如,有一张订单表(order)放在数据库中,全部的订单均可以在order表中查到。

单库多表

随着订单数量的增长,order表的数据量会愈来愈大,当数据量达到必定程度的时候,对order表的查询会变慢,从而影响整个DB的性能。

另外,随着需求的迭代,若是增长添加一列的时候,mysql会锁表,期间全部的读写操做只能等待,别无他法。

这时候,能够将order进行水平的切分,产生多个表结构彻底同样的order表。好比:order_01,order_02....,order_n,那么order_01+order_02+order_n的数据是一份完整的订单数据。

这个水平切分,简单的作法如:

按数量切分,1~1000的存在第一张表,1001~2000存在第二张表;

按时间切分,好比:2019年1月份存在第一张表,2019年2月份存在第二张表;还能够按照id的哈希值进行切分,等等等等

多库多表

随着数据量增长,单台数据库的硬件存储不够了,而且,随着查询量的增长,单台数据库服务器已经没办法支撑。这时候就须要对数据库进行水平区分。

好比按地区分库,一个省份在一个物理数据库等等

任何事情都有两面性,分库分表也不例外,若是采用分库分表,会引入新的的问题

1.分布式事务问题

作了垂直分库或者水平分库之后,就必然会涉及到跨库执行SQL的问题,就会引起互联网界的老大难问题-"分布式事务"。那么要如何解决这个问题呢?

使用分布式事务中间件使用MySQL自带的针对跨库的事务一致性方案(XA),不过性能要比单库的慢10倍左右。可否避免掉跨库操做(好比将用户和商品放在同一个库中)2.跨库join的问题

分库分表后,表之间的关联操做将受到限制,就没法join位于不一样分库的表,也没法join分表粒度不一样的表, 结果本来一次查询可以完成的业务,可能须要屡次查询才能完成。

那么要如何解决这个问题呢?

简单的解决方法:

全局表:基础数据,全部库都拷贝一份。字段冗余:把须要join的字段冗余在各个表中,这样有些字段就不用join去查询了。系统层组装:应用端先分别查询出全部复核条件的,而后在应用端组装起来,相似于一个mapreduce的过程(较复杂)。3.横向扩容的问题

当咱们使用哈希取模作分表的时候,针对数据量的递增,可能须要动态的增长表,此时就须要考虑数据迁移的问题。

原来使用的是hash后对8进行取模,那么,数据是均分在8个表(库)上。

若是8个表不够的时候,咱们要扩展到16个表,这时候,咱们hash后对16取模,新数据是没有问题的,旧数据就会发生错乱。

若是哈希后是9,那么,原来咱们对8取模后,是1,会到表1进行查询;可是,如今咱们是对16取模,那么是到表9进行查询的,而这个数据在表9又不存在,所以,就会找不到数据了

4.结果集合并、排序的问题

由于咱们是将数据分散存储到不一样的库、表里的,当咱们查询指定数据列表时,数据来源于不一样的子库或者子表,就必然会引起结果集合并、排序的问题。

若是每次查询都须要排序、合并等操做,性能确定会受很是大的影响。

上面列出了分库分表的常见的一些,总的来讲:

能不切分尽可能不要切分,若是没有达到几百万,一般无需分库分表若是必定要切分,必定要选择合适的切分规则,提早规划好。若是必定要切分,尽可能经过数据冗余或表分组来下降跨库 Join 的可能。对于如今市面上有好几种数据库中间件,这些中间件对数据 Join 实现,个中滋味,只能本身体会。业务读取尽可能少使用多表 Join。数据尽量的比较均匀分布数据到各个节点上

相关文章
相关标签/搜索