一、业务分库
业务分库指的是按照业务模块将数据分散到不同的数据库服务器。例如,一个简单的电商网站,包括用户、商品、订单三个业务模块,我们可以将用户数据、商品数据、订单数据分开放到三台不同的数据库服务器上,而不是将所有数据都放在一台数据库服务器上
业务分库能够分散存储和访问压力,但也带来了新的问题
1)join操作问题
业务分库后,原本在同一个数据库中的表分散到不同数据库中,导致无法使用SQL的join查询
2)事务问题
原本在同一个数据库中不同的表可以在同一个事务中修改,业务分库后,表分散到不同的数据库中,无法通过事务统一修改
二、分表
单表数据拆分有两种方式:垂直分表和水平分表
垂直分表:表记录相同但包含不同的列。例如,上图的垂直拆分,会把表切分成两个表,一个表包含ID、name、age、sex列,另外一个表包含ID、nickname、description列
水平分表:表的列相同但包含不同的行数据。例如,上图的水平拆分,两个表都包含ID、name、age、sex、nickname、description列,但是一个表包含的是ID从1到999999的行数,另一个表包含的是ID从1000000到9999999
单表进行切分后,是否要将切分后的多个表分散在不同的数据库服务器中,可以根据实际的切分效果来确定,并不强制要求单表切分为多表后一定要分散到不同数据库中。原因在于单表切分为多表后,新的表即使在同一个数据库服务器中,也可能带来可观的性能提升,如果性能能够满足业务要求,是可以不拆分到多台数据库服务器的
1、垂直分表
垂直分表适合将表中某些不常用且占了大量空间的列拆分出去
垂直分表引入的复杂性主要体现在表操作的数量要增加
2、水平分表
水平分表适合表行数特别大的表
水平分表相比垂直分表,会引入更多的复杂性,主要表现在下面几个方面:
1)、路由
水平分表后,某条数据具体属于哪个切分后的子表,需要增加路由算法进行计算,这个算法会引入一定的复杂性
常见的路由算法有:
范围路由:选取有序的数据列作为路由的条件,不同分段分散到不同的数据库表中
范围路由设计的复杂点主要体现在分段大小的选取上,分段太小会导致切分后字表数量过多,增加维护复杂度;分段太大可能会导致单表依然存在性能问题
范围路由的优点是可以随着数据的增加平滑地扩充新的表,例如现在的用户是100万,如果增加到1000万,只需要增加新的标就可以了,原有的数据不需要动
缺点是分布不均匀,假如按照1000万来进行分表,有可能某个分段实际存储的数据量只有100条,另外一个分段实际存储的数据量有900万条
Hash路由:选取某个列(或者某几个列组合)的值进行Hash运算,然后根据Hash结果分散到不同的数据库表中。以用户ID为例,假如一开始就规划了10个数据库表,路由算法可以简单地用user_id%10的值来表示数据所属的数据库表编号,ID为985的用户放到编号为5的子表中,ID为10086的用户放到编号为6的子表中
Hash路由的优点是表分布比较均匀,缺点是扩充新的表很麻烦,所有数据都要重分布
配置路由:配置路由就是路由表,用一张独立的表来记录路由信息。以用户ID为例,新增一张user_router表,这个表包含user_id和table_id两列,根据user_id就可以查询对应的table_id
配置路由设计简单,使用起来非常灵活,尤其是在扩充表的时候,只需要迁移指定的数据,然后修改路由表就可以了
配置路由的缺点就是必须多查询一次,会影响整体性能;而且路由表本身如果太大,性能同样可能成为瓶颈
2)、join操作
水平分表后,数据分散在多个表中,如果需要与其他表进行join查询,需要在业务代码或者数据库中间件中进行多次join查询,然后将结果合并
3)、count()操作
count()相加:在业务代码或者数据库中间件中对每个表进行count()操作,然后将结果相加。这种方式实现简单,缺点就是性能比较低
记录数表:新建一张表,假如表名为记录数表,包含table_name、row_count两个字段,每次插入或者删除子表数据成功后,都更新记录数表
4)、order by操作
水平分表后,数据分散到多个子表中,排序操作无法在数据库中完成,只能由业务代码或者数据库中间件分别查询每个子表中的数据,然后汇总进行排序