什么是分库分表
分库,显而易见,就是一个数据库分成多个数据库,部署到不同机器。
分表,就是一个数据库表分成多个表。
那么为什么需要分库分表呢?
为什么需要分库分表?
首先我们要明确一个问题,单一的数据库是否能够满足公司目前的线上业务需求,比如,我们的用户表,可能有几千万,甚至上亿的数据,阿粉只是说可能,如果有这么多用户,那必然是大公司了,那么这个时候,如果你不分表也不分库的话,那么数据了上来的时候,稍微一个不注意,MySQL单机磁盘容量会撑爆,但是如果拆成多个数据库,磁盘使用率大大降低。
这样就把磁盘使用率降低,这是通过硬件的形式解决问题,就像阿粉所有,如果你的数据量是巨大的,这时候,SQL 如果没有命中索引,那么就会导致一个情况,查这个表的SQL语句直接把数据库给干崩了。
即使SQL命中了索引,如果表的数据量 超过一千万的话, 查询也是会明显变慢的。这是因为索引一般是B+树结构,数据千万级别的话,B+树的高度会增高,查询自然就变慢了,当然,这是题外话了。
那么我们接下来就得说说如何进行分库和分表的操作了,今天阿粉就讲一下这个如何进行进行分库分表。
分库分表方案
分库分表方案,不外乎就两种,一种是垂直切分,一种是水平切分。
但是总有做开发的小伙伴不知道这垂直切分和水平切分到底是什么样的,为什么垂直切分,为什么水平切分,什么时候应该选择垂直切分,什么时候应该选择水平切分。
有人是这么说的,垂直切分是根据业务来拆分数据库,同一类业务的数据表拆分到一个独立的数据库,另一类的数据表拆分到其他数据库。
有些人不理解这个,实际上垂直切分也是有划分的,上面描述的是垂直切分数据库,可能容易让很多人不太理解,但是如果是垂直切分表,那么肯定百分之90的人都能理解。
我们又一张Order表,表中有诸多记录,比如我们设计这么一张简单的表。
字段有如下。
id | order_id | order_date | order_type | order_state |
1 | cd96cff0356e483caae6b2ff4e878fd6 | 2022-06-11 13:57:11 | 支付宝 | 1 |
2 | e2496f9e22ce4391806b18480440526a | 2022-06-12 14:22:33 | 微信 | 2 |
3 | 9e7ab5a1915c4570a9eaaaa3c01f79c1 | 2022-06-12 15:21:44 | 现金 | 2 |
以上是我们的简化版Order表,如果我们想要垂直切分,那么应该怎么处理?
直接拆分成2个表,这时候就直接就一份为2 ,咔的一下拆分成两个表?
Order1
id | order_id | order_date |
1 | cd96cff0356e483caae6b2ff4e878fd6 | 2022-06-11 13:57:11 |
2 | e2496f9e22ce4391806b18480440526a | 2022-06-12 14:22:33 |
3 | 9e7ab5a1915c4570a9eaaaa3c01f79c1 | 2022-06-12 15:21:44 |
Order2
id | order_type | order_state |
1 | 支付宝 | 1 |
2 | 微信 | 2 |
3 | 现金 | 2 |
这时候我们的主键ID保持的时一致的,而这个操作,就是垂直拆分,分表的操作。
既然我们说了垂直拆分,那么必然就有水平拆分。
什么是水平拆分呢?
实际上水平拆分的话,那真的是只有一句话。
按照数据来拆分
水平拆分数据库:将一张表的数据 ( 按照数据行) 分到多个不同的数据库.每个库的表结构相同. 每个 库都只有这张表的部分数据,当单表的数据量过大,如果继续使用水平分库, 那么数据库的实例 就会不断增加,不利于系统的运维. 这时候就要采用水平分表。
水平拆分分表: 将一张表的数据 ( 按照数据行) , 分配到同一个数据库的多张表中,每个表都只有一部 分数据。
我们来看看Order表进行水平拆分的话,是什么样子的。
Order1
id | order_id | order_date | order_type | order_state |
1 | cd96cff0356e483caae6b2ff4e878fd6 | 2022-06-11 13:57:11 | 支付宝 | 1 |
2 | e2496f9e22ce4391806b18480440526a | 2022-06-12 14:22:33 | 微信 | 2 |
Order2
id | order_id | order_date | order_type | order_state |
3 | 9e7ab5a1915c4570a9eaaaa3c01f79c1 | 2022-06-12 15:21:44 | 现金 | 2 |
实际上就是水平的把表数据给分成了2份,这么看起来是不是就很好理解了。
分库分表带来的问题
事务问题首先,分库分表最大的隐患就是,事务的一致性, 当我们需要更新的内容同时分布在不同的库时,不可避免的会产生跨库的事务问题。原来在一个数据库操作,本地事务就可以进行控制,分库之后 一个请求可能要访问多个数据库,如何保证事务的一致性,目前还没有简单的解决方案。
无法连表的问题
还有一个就是,没有办法进行连表查询了,因为,, 原来在一个库中的一些表,被分散到多个库,并且这些数据库可能还不在一台服务器,无法关联查询。所以相对应的业务代码可能就比较多了。
分页问题
分库并行查询时,如果用到了分页 每个库返回的结果集本身是无序的, 只有将多个库中的数据先查出来,然后再根据排序字段在内存中进行排序,如果查询结果过大也是十分消耗资源的。
阿粉之前用过一次分页,直接能把线上CPU瞬间会有一个顶峰值。所以,慎重呀。
分库分表的技术
目前比较流行的就两种,一种是MyCat,另外一种则是Sharding-jdbc,都是可以进行分库的。
MyCat是一个数据库中间件,Sharding-jdbc是以 jar 包提供服务的jdbc框架。
如果要是让阿粉选择,那么阿粉绝对会选择最方便快捷的,也就是jar包的形式来操作。
Mycat和Sharding-jdbc 实现原理也是不同。
Mycat的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分库分表分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
而Sharding-JDBC的原理是接受到一条SQL语句时,会陆续执行SQL解析 => 查询优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并 ,最终返回执行结果。