✅订单号用了基因法之后,二次分表怎么办?
典型回答
上面的文档中我们介绍过分库分表中,为了让订单号也可以实现快速查询,我们采用基因法来编码订单号,也就是把分表结果放到订单号上面去,这样基于订单号就能直接精准找到具体的单表做查询了。
那么,有个关键问题,那就是原来的表如果是分成了128张,但是后面不够了,要重新分表成256,怎么办?老的订单没办法迁移了,因为订单号肯定是不能变的,而一旦数据迁移,就没办法查询到之前的订单了。那么可行的方案有哪些呢?
网上有很多乱七八糟的方案,我认为可行的就以下两种。
1、把分表字段编码到订单号上
所谓基因法,其实只要订单上有分表相关的基因就行了,但是不要求说一定要是基于分表结果做基因。也可以直接用分表字段做基因。
比如,原来我们是这样的,分成128张表,用buyer_id做分表字段,取模作为分表算法。
数据插入的时候
1、分表结果 = buyer_id % 128 ,如 23
2、分表结果编码到订单号中,如xxxx0023
那么在查询的时候:
1、基于订单号xxxx0023,计算出他的物理表是0023这张表,那么就直接去这张表查询即可。
但是,如果我们换一个方案,数据插入的时候是这样的:
1、buyer_id编码到订单号中,如xxxx32132145
查询的时候:
1、从订单号xxxx32132145中解析出用户id:32132145
2、基于32132145用户id,计算出具体的物理表
3、直接去具体的物理表做查询
如果是这样的话,你想想,我们是不是怎么扩容都可以。只要在扩容后做数据迁移就行了,因为我并没有在订单号上记录具体的分表信息,而是记录的用户id的信息,只要库容之后,我把分表算法同步改了就行,即之前是对128取模,现在是对256取模了。
优点:
1、完全向下兼容
缺点:
1、用户id可能过长
- 这个也可以通过固定的保留后几位实现,比如一般就保留后四位就够了
2、需要做数据迁移
2、新老共存
这个方案很简答,其实就是原来的订单按照旧基因法分到老的 128 张表中。扩容后,新订单写入新的256分表中。这样在查询的时候在查询时,根据订单ID判断是老订单还是新订单,然后走不同的表。
比如老订单是20位,新订单则设置个21位。然后通过订单号的长度来判断,如果是20位的,则通过老的算法去路由,如果是21位的,则通过新的算法去路由。
随着时间慢慢推移,老订单就可以统一迁移到历史表里面去了,那么老的128张表就可以慢慢废弃掉了。
优点:
- 不需要迁移旧数据。
- 风险较小
缺点:
- 路由逻辑会更加复杂。
- 跨分表聚合查询时需要查多个分区。
3、其他方案
我之前看过,网上还给出一些其他的方案,比如一致性hash,中间表等。
都是扯淡的。一致性hash根本能解决问题,还是那个原因,订单号是不能变的。虽然一致性hash可以让迁移量更小,但是还是要迁移的。
另外,有人大聪明说我建一个中间路由表,记录下每个订单再哪张表、、、、想想都好笑。
另外,有人说我搞一个中间层服务,然后让他去做统一处理,首先行肯定是行,但是这个方案太泛了,面试的时候提只会被喷。因为面试官肯定还会问你,这个中间路由层他又是怎么做的呢?你还要回到具体的可落地方案上。
总结
如果你在最开始就考虑可能要二次分表,那么就用第一个方案。
如果最开始没想好,后面才要库容的,那就用第二个方案。