分库分表就是为了解决由于数据来量过大而导致数据库性能降低的问题,将原来独立的数据库拆分成若干个数据库组成,将数据大表拆分成若干个数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提高数据库性能的目的。
1. 垂直分表
定义: 将一个表按照字段分成多张表,每个表存储其中一部分字段。
示例: 将商品的商品描述单独拆分成一张表
好处:
- 为了避免IO争抢并减少锁表的几率
- 充分发挥热门数据的操作效率(冷热字段分离)
为什么大字段IO效率低?
- 由于数据量本身大,需要更长的读取时间
- 跨页,页是数据库存储单位,很多查找及定位操作都是以页为单位,单页内的数据行越多数据库整体性能越好,而大字段占用空间大,单页内存储行数少,因此IO效率较低
- 数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频流较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能
拆分原则:
- 把不常用的字段单独放在一张表
- 把text,blob等大字段拆分出来放在附表中
- 经常组合查询的列放在一张表中
2. 垂直分库
通过垂直分表性能得到了一定的提升,但数据还是限制在一台服务器,库内垂直分表只解决了单一表数据量过大的问题,但没有将表分布在不同的服务器上,因此每个表还是竞争同一个物理机的CPU、内存、网络IO、磁盘。
垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。
示例: 商品相关表放置在商品库,店铺相关表放置在店铺表。
好处:
- 解决业务层面的耦合,业务清晰
- 能对不同的业务的数据进行分级管理、维护、监控、扩展等
- 高并发场景下,垂直分库一定程度的提升IO、数据库连接数、减低单机硬件资源的瓶颈
垂直分库通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。
3. 水平分库
水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。
对比: 垂直分库是把不同表拆到不同数据库中,水平分库是对数据行的拆分,不影响表结构
好处:
- 提高了单库大数据,高并发的性能瓶颈
- 提高了系统的稳定性及可用性
稳定性体现在IO冲突减少,锁定减少;可用性指某个库出问题,部分可用
4. 水平分表
水平分表是在同一数据库内,把一个表的数据按一定规则拆分到多个表中(对数据行的拆分,不影响表结构)。
好处:
- 优化单一表数据量过大而产生的性能问题
- 避免IO争抢并减少锁表的几率
总结
- 垂直分表
可以把一个宽表的字段按访问频次,是否大字段的原则拆分为多个表,这样既能使业务清晰,还能提升部分性能。
拆分后,尽量从业务角度避免联查,否则性能方面将得不偿失 - 垂直分库
可以把多个表按业务耦合松紧归类,分别存放在不同的库,这些库可以分布在不同服务器,从而使访问压力被多服务器负载,大大提升性能,同时能提高整体架构的业务清晰度,不同的业务库可根据自身情况定制优化方案。 - 水平分库
可以把一个表的数据(按数据行)分到多个不同的库,每个库只有这个表的部分数据,这些库可以分布在不同服务器,从而使访问压力被多服务器负载,大大提升性能。它不仅需要解决跨库带来的所有复杂问题,还要解决数据路由的问题。 - 水平分表
可以把一个表的数据(按数据行)分到多个同一个数据库的多张表中,每个表只有这个表的部分数据,这样做能小幅提升性能,它仅仅作为水平分库的一个补充优化。
一般来说,在系统设计阶段就应该根据业务耦合松紧来确定垂直分库,垂直分表方案,在数据量及访问压力不是特别大的情况,首先考虑缓存、读写分离、索引技术等方案。若数据量极大,且持续增大,再考虑水平分库水平分表方案。
分库分表带来的问题
分库分表有效的缓解了单机和单库带来的性能瓶颈和压力,突破网络IO、硬件资源、连接数的瓶颈、同时也带来了一些问题。
1. 事务一致性
由于分库分表把数据分布在不同库甚至不同服务器,不可避免会带来分布式事务问题。
2. 跨节点关联查询
示例:垂直分库后【商品信息】和【店铺信息】不在同一数据库,甚至不在一台服务器,无法进行关联查询。
可将原关联查询分为两次查询,第一次查询的结果集中找出关联数据ID,然后根据ID发起第二次请求得到关联数据,最后将获得到的数据进行拼装。
3. 跨节点分页、排序、函数
跨节点多库进行查询时,limit分页,Order By排序等问题,就变得比较复杂。
需要先在不同的分片节点中将数据进行排序并访问,然后将不同分页返回的结果集进行汇总和再次排序。
在使用Max、Min、Sum、Count之类的函数进行计算的时候,与排序分页同理,也需要先在每个分页上执行相应的函数,然后将各个分片的结果集进行汇总和再次计算,最终将结果返回。
4. 主键避重
在分库分表环境中,由于表中数据同时存在不同数据库中,主键值平时使用的自增长将不满足需求,某个分区数据生成的ID无法保证全局唯一。因此需要单独设计全局主键,以避免跨库主键重复问题。
5. 公共表
实际的应用场景中,参数表、数据字典表等都是数据量较小,变动少,而且属于高频联合查询的依赖表。
可以将这类表在每个数据库都保存一份,所有对公共表的更新操作都同时发送到所有分库执行。
由于分库分表之后,数据被分散在不同的数据库、服务器。因此,对数据的操作也就无法通过常规方式完成,并且它还带来了一系列的问题。
数据库分片方案
- 客户端代理
分片逻辑在应用端,封装在Jar包中,通过修改或者封装JDBC层来实现。
示例:当当网的Sharding-JDBC、阿里的TDDL - 中间件代理
在应用和数据中间加了代理层,分片逻辑统一在中间件服务中。
示例:Mycat、360的Atlas、网易的DDB