为什么要使用分库分表?什么时候使用分库分表?
关系数据库的性能容易成为系统性能的瓶颈,读写分离分散了数据库的读写压力,但并没有分散存储压力,当数据量达到千万甚至上亿时
- 数据量太大,读写性能下降,即使使用索引,索引也会很大,性能也会下降
- 数据库文件很大,备份、恢复耗时长
- 数据库文件越大,数据丢失风险越高,发生故障时数据丢失量往往很大
当数据库并发量很大、存储的数据量很大时,往往需要分库分表,分担单个数据库的存储压力、读写压力,提高数据库性能。
有2种切分策略:水平切分、垂直(纵向)切分。
垂直切分
垂直分库
根据数据表的耦合度进行拆分,将同一数据库中关联度低的表拆分出来,放在新的数据库中。
垂直分表
①如果某张表的字段很多,可以把不常用的字段拆分出来,单独放到一张新表中,实现冷热数据分离。
②或者把内容较多、较大的字段拆分出来。数据库底层通过数据页存储数据,一条记录占用空间很大会导致跨页,拉低性能。
在字段很多的情况下,通过大表拆小表,方便开发、维护,也能避免跨页问题。
另外,数据库以行为单位将数据加载到内存,表中字段内容越短,能加载到内存的数据(记录数)越多。冷热分离后,热点表中热点字段多、访问频率高,缓存命中率也就很高,大大提高了数据库的检索性能。
垂直切分的缺点
- 垂直分库使原本在同一数据库中的表拆分到不同数据库(节点)中,操作不同数据库中的表要使用分布式事务,事务的使用变得复杂。另外,跨库的多表关联查询性能较差。
- 垂直分表使原本一张表中的字段拆分到多张表中,不同表之间的操作需要多表关联查询,连接查询性能较差
总之,垂直切分提升了单表查询的性能,但增加了多表关联查询的次数。
水平切分
垂直切分只是减少了单表的字段数,但并没有减少单表的记录数。水平切分是将单表中的记录拆分到多张表中。
按新表存放位置可分为2种
- 库内分表 将拆分出来的新表放在同一数据库中
- 分库分表 将拆分出来的新表放在不同的数据库中
库内分表只解决了单表记录数过多的问题,但拆分出来的表竞争同一个机器的CPU、内存、网络IO,并没有减轻数据库的存储压力。
分库分表解决了单表记录数过多的问题,也分散了单个数据库的存储压力,但垮库操作要使用分布式事务,事务难度加大,跨库的多表关联查询性能较差。
水平切分都有的缺点:聚合函数、order by排序、group by分组使用不方便,要从多个子表中查数据,然后自己汇总。
2种记录拆分方式
1、根据范围进行拆分
eg. 根据id字段的范围进行划分,1 ~ 9999999放到一张表中,10000000~199999999放到一张表中,以此类推。
关键在于范围的选取上,分段太小会导致子表数量过多,增加维护难度;分段太大则拆分意义不大。通常,单个分段大小在100W ~ 2000W之间。
优点
- 扩容方便。随着记录数的增加,可以直接使用新表来存储数据,原有数据不需要动
- 单表大小(记录数)可控
2、根据hash值进行拆分
eg. 商品信息表,计算type字段的hash值,把hash值相同的字段划到同一表中,一张子表存储同一类型的商品。
路由表
水平切分,随着记录数的增加,子表数量会增加(变化),不能在代码中写死子表名。新建一张表作为路由表,一列存储子表名,
- 如果是以范围拆分的,使用start_index、end_index 2列分别存储子表范围
- 如果是以hash方式拆分的,用一列存储子表对应的常量,eg. 存储商品类型(type)。
操作数据库时,先查路由表得到记录所在子表,再去操作子表。要多查一次,降低了性能,所以除非单表记录数特别多,否则不要轻易水平分表。
就算要水平分表,子表数量也不宜太多,一方面难以维护,另一方面子表太多会导致路由表中记录数很多,查路由表时间开销大。
总结
分库分表,性能有提升之处,也有降低之处。分库分表的主要作用是减轻单机数据库的存储压力,性能考虑还再其次。
切分原则:先做垂直切分、再做水平切分。
比如user表,垂直切分为2张表
- user_base:存放常用字段
- user_extra表:存放不常用的字段
2张表中都有user_id字段,用于唯一标识记录。
此时还可能存在单表行数过多的问题,需要水平切分。
预估要分散到几个库中,每个库又要分散到几个表中,对user_id取模,将模值相同的记录划分到同一个库中,再对同一个库中的user_id取模,将模值相同的记录划分到同一个表中。
假设用户量1亿,每个库2500w个用户记录,需要分4个库;每张表500w条记录,每个库又分为5个表。user_id % 4得到该条记录所在的库,user_id % 5得到该条记录所在的表。
分库分表造成的问题|要考虑的点
- 分布式主键(id)问题
- 分布式事务问题,如何保证多个库中的数据一致性
- 存在大量关联查询的问题:可以拆分查询,使用冗余字段、空间换时间。
分库分表带来的问题很复杂,不到万不得已,不要轻易分库分表。