菜菜哥,上次听你给我讲了分库的情况后,我明白了很多,能再给我讲讲分表吗
有收获就好,分表其实有很多情况和分库类似
还有不一样的情况吗?
有呀,本来数据库和表是不同层面的东西,肯定有差异
那你给讲讲呗
讲可以,一杯coffee如何?
为什么分
在正式开始之前,菜菜还是要强调一点,你的数据表是否应该分,需要综合考虑很多因素,比如业务的数据量是否到达了必须要切分的数量级,是否可以有其他方案来解决当前问题?我不止一次的见过,有的leader在不考虑综合情况下,盲目的进行表拆分业务,导致的情况就是大家不停的加班,连续几周996,难道leader你不掉头发吗?还有的架构师在一个小小业务初期就进行表拆分,大家为了配合你也是马不停蹄的加班赶进度,上线之后反而发现业务数据量很小,但是代码上却被分表策略牵制了太多。拆表引起的问题在特定的场景下,有时候代价真的很大。
数据库表的拆分解决的问题主要是存储和性能问题,mysql在单表数据量达到一定量级后,性能会急剧下降,相比较于sqlserver和Oracle这些收费DB来说,mysql在某些方面还是处于弱势,但是表的拆分这个策略却适用于几乎所有的关系型数据库。
数据库进行表拆分不要太盲目
分表策略
表的拆分和数据库的拆分有相似之处,但是拆分的规则也有不同。以下的拆分规则针对的是拆分一个表。
横向切分
横向切分是诸多业务中最常用的切分方式,本质是把一个表中的数据行按照规则分散到多个表中,比如最常见的按照ID范围,按照业务主键的哈希值等。至于表数据到达什么数量级之后进行切分,这和表中存的数据格式有关,比如一个表只有几列的int字段肯定要比几列text类型的表存储的极限要高。姑且认为这个极限是1000万吧。但是作为一个系统的负责人或者架构师来说,当表的数据量级到达千万级别要引起重视,因为这是一个系统性能瓶颈的隐患。
相对于数据表的横向切分,在符合业务优化的场景下我更倾向于做表分区,按照规则把不同的分区分配到不同的物理磁盘,这样的话,业务里的sql语句几乎可以不用改动。我司的一个sqlserver数据库,某个业务的表做了表分区之后,已经到达几十亿级别的数据量,但是查询和插入速度还是能满足业务的需求(优化一个系统还是要花精力优化业务层面)。
垂直切分
说到垂直拆分,表也可以按照业务来拆分,比如一个数据库中有用户的信息,根据业务可以划分为基础信息和扩展信息,如果对业务有利,完全可以拆分为基础信息表和扩展信息表。当然也可以按照别的规则来拆,比如把访问频繁的信息拆分成一个表,其他不频繁的信息拆分成一个表,具体的拆分规则还是要看当时要解决的问题是什么。垂直拆分可能会引入一定复杂性,比如原来查询一个用户的基础信息和扩展信息可以一次性查询出结果,分表之后需要进行Join操作或者查询两次才能查询出结果。
分表代价
1. 数据表垂直切分之后,原来一次查询有可能会变为连表的join查询,在一定程度上会有性能损失。
2. 数据表横向切分需要一定的规则,常用的主要有两种规则:范围切分和哈希值切分。范围切分是指按照某个字段的范围来切分,比如用户表按照用户ID来切分,id为1到10万的位于User表1中,100001到200000万的位于User2中,这样切分的优势是,可以无限的扩容下去,不用考虑数据迁移的问题,劣势就是新表和旧表数据分布不均匀,而且分表的范围选取有一定难度,范围太小会导致表太多,太大会导致问题根本上没有解决的困惑。另外一种分表策略就是把某一列按照哈希值来路由到不同的表中,同样以用户ID为例,假如我们一开始就规划了10个数据库表,路由算法可以简单地用 user_id %10的值来表示数据所属的数据库表编号,ID为985的用户放到编号为 5的子表中,ID为10086的用户放到编号为 6 的字表中。这种切分规则的优势是每个表的数据分布比较均匀,但是后期扩容会设计到部分数据的迁移工作。
3. 表拆分之后如果遇到有order by 的操作,数据库就无能为力了,只能由业务代码或者数据库中间件来完成了。
4. 当有搜索的业务需求的时候,sql语句只能是Join多个表来进行连表查询了,类似的还有统计的需求,例如count的统计操作。
●程序员过关斩将--你为什么还在用存储过程?●程序员过关斩将--小小的分页引发的加班血案●程序员修神之路--问世间异步为何物?●程序员修神之路--提高网站的吞吐量?●程序员修神之路--?分布式高并发下Actor模型如此优秀?●程序员过关斩将--论商品促销代码的优雅性●程序员过关斩将--你的面向接口编程一定对吗?●程序员修神之路--高并发下为什么更喜欢进程内缓存●程序员修神之路--高并发优雅的做限流