高性能数据库之 分库分表

前言

前面的读写分离,分散了数据库读写操作的压力,没有分散存储压力,当数据量很大时,单台数据库服务器就会出现性能瓶颈,主要在以下几方面:

  • 数据量太大,读写性能下降
  • 数据文件也会变得很大, 备份恢复时间变长

所以,需要控制单台数据库服务器数据量大小,分库分表,他来了!先从分库开始说起。

分库

一般都是业务分库,也就是按照业务模块将数据分散到各个数据库,比如一个电商网站,可以分为用户、商品和订单库。原本一台数据库服务器的数据分散了三个库。

需要注意的点
  1. join操作问题
    以前的表都在一个库中,关联表很容易,分库后,跨库关联是不可能的事,只能通过两步查询的方式。
    比如,做数据分析时,查询20-30岁购买量前十名的商品列表。就需要先查出年龄合适的用户列表,接着去查询订单。
  2. 事务问题
    现在分布式事务也有写解决方案,但是效率也成了问题。
  3. 成本问题
    分库前一台服务器搞定,分库后就不止一台了。

分表

同一业务的单表数据也有可能达到性能瓶颈,如果单表达到了亿级,分表将会是个好选择。
单表数据拆分分为 垂直分表水平分表
垂直分表和水平分表
例如,示意图中的垂直切分,会把表切分为两个表,一个表包含 ID、name、age、sex 列,另外一个表包含 ID、nickname、description 列。

示意图中的水平切分,会把表分为两个表,两个表都包含 ID、name、age、sex、nickname、description 列,但是一个表包含的是 ID 从 1 到 99999999 的行数据,另一个表包含的是 ID 从 100000000 到 999999999 的行数据。

上面这个示例比较简单,只考虑了一次切分的情况,实际架构设计过程中并不局限切分的次数,可以切两次,也可以切很多次。分表后这些表可在一个数据库服务器上,也可以分散在多个服务器上。

需要注意的点
垂直分表

垂直分表可以将一些不常用且占用空间大的字段拆分出去,例如图上的用户信息,description字段并不需要在查询列表时显示,而且字段长度比较长,放在另一个表比较合适。

这样做也有一点不好,就是如果查看用户详情,需要查询所有信息,这里就需要进行两次查询。

水平分表

水平分表适合表行数特别大的表,有的公司要求单表行数超过 5000 万就必须进行分表,这个数字不是标准,可以作为参考.
关键还是要看表的访问性能。对于一些比较复杂的表,可能超过 1000 万就要分表了;而对于一些简单的表,即使存储数据超过 1 亿行,也可以不分表。
但不管怎样,当看到表的数据量达到千万级别时,作为架构师就要警觉起来,因为这很可能是架构的性能瓶颈或者隐患。

水平分表相比垂直分表,会引入更多的复杂性,主要表现在下面几个方面:

  • 路由
    水平分表后,某条数据属于哪张表是需要计算的。
    常用的路由算法有:
    1. 范围路由:
            如果分表时一百万为分表范围,1999999为第一张表,10000001999999数据在第二张表。
            这个范围需要根据实际表情况来决定,范围小会分成更多的表。如果简单的表每100万一张表,可能就没每1000万一张表更好。
            使用这种方式,每个表的数据量会有大差距,如果此时有一百万零几条,一百万条数据分两个表,第一个表会有百万数据,第二个表只有几条数据。
    2. Hash路由:
            选取某个列的值进行 Hash 运算,然后根据 Hash 结果分散到不同的数据库表中。
            以用户 ID 为例,假如我们一开始就规划了 10 个数据库表,路由算法可以简单地用 user_id % 10 的值来表示数据所属的数据库表编号,ID 为 985 的用户放到编号为 5 的子表中,ID 为 10086 的用户放到编号为 6 的字表中。
            这种设计可以改善范围路由的不足,设计复杂点在初始表数量的选择上,数量太多维护麻烦,数量少了性能不会是最佳。
    3. 配置路由:
            配置路由就是用一张表来记录路由信息。
            同样以用户 ID 为例,我们新增一张 user_router 表,这个表包含 user_id 和 table_id 两列,根据 user_id 就可以查询对应的 table_id。
            配置路由设计简单,使用起来非常灵活,尤其是在扩充表的时候,只需要迁移指定的数据,然后修改路由表就可以了。
            配置路由的缺点就是必须多查询一次,会影响整体性能;

  • join 操作
            水平分表后,数据分散在多个表中,如果需要与其他表进行 join 查询,需要在业务代码或者数据库中间件中进行多次 join 查询,然后将结果合并。

  • count() 操作
            水平分表后,虽然物理上数据分散到多个表中,但是他们还是一类数据,还会有需要记录总量的场景。
    这时有两个方法:

    1. count相加:就是将所有表的记录数相加,得到总记录数
    2. 记录数表,用一个表记录多个水平表的数量,有变化时候进行总数的加减。
  • order by操作
            水平分表后,数据被分散在多个表中,排序操作就不能在数据库中进行了,只能用代码进行排序。

实现方式

分库分表的实现方式比较复杂,需要判断需要操作哪张表,如果遇到关联表、查询记录数、排序等,需要进行特速处理。

总结

分库分表是一种空间换时间的方式,当前数据库性能出现瓶颈时,可以考虑这种方法,但是这并不是首选方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值