求教:如何实现千亿级别多商户订单表的主键及表分区设计?

如题,基于OceanBase,如何实现千亿级别的多商户订单表的主键和表分区设计 ?

需求背景:

  1. 商户可能在数万级别
  2. 订单数据预期在数千亿级别
  3. 每天的订单量在 10亿级别(可能更高)
  4. 只需保留最近3个月的订单数据
  5. 商户之间的数据差别很大,有些可能每天过亿,有些可能 等于 0

很明显,这么大的数据量,不通过表分区来分片存储,是很难扛得住的。
既然要考虑分区,常见的表分区方案如下:

  1. 按照 商户ID 分片
  2. 按照 时间 (按天 甚至 按小时) 分片
  3. 按照 商户ID + 按时间 分片
  4. 按照 主键ID 分片

此外,OceanBase 要求 分片键 必须是 主键 或 唯一键的 一部分。
OceanBase 也建议使用业务上的唯一键作为主键ID,针对订单表来说,也就是 商户ID + 订单号

基于上述已知条件,我们再来看看各种方案:

先看 方案1,可能存在如下缺陷:

  1. 分片不够均衡,某些分片的数据可能很庞大(比如百亿级别)

再看 方案2,可能存在如下缺陷:

  1. 时间字段 不是OceanBase推荐主键 商户ID + 订单号 的一部分,似乎无法分片 ?或者 OceanBase 的建议不可行 ?
  2. 存在明显的 热点数据问题,当前时间的分片就非常繁忙,其他历史分片就相对很空闲。

接着看 方案3,可能存在如下缺陷:

  1. 同方案2一样,时间字段不属于主键的一部分。
  2. OceanBase最多仅支持 65536 个分区,无法满足业务要求。

最后看 方案4,可能存在如下缺陷:

  1. 所有非主键ID的查询,都需要多分区聚合(意即遍历所有分区)。

针对上述情况,不知道大家有没有更好的思路或建议 ?
在千亿级别数据下,基于OceanBase,多少分区是比较合适的呢 ?

时间是限制了不能用做主键么

之前 OceanBase 官方推荐使用业务上的唯一键作为主键,在这个表中,那就是 商户ID + 订单号
当然,我们在实际业务中,也可以不遵循该建议。

你的意思是,建议按 小时 维度进行表分区,用 时间相关字段作为主键 吗?
这里有几个问题值得讨论:

  1. 打算用什么时间字段做主键呢 ?毫秒级别的 创建时间 似乎并不能保证 唯一,或者考虑用什么样的联合主键?
  2. 如果用 时间字段 作为主键,那么 当天/当前小时 的数据就会写入到同一个分片,但热点数据如果都集中写入在一个分片的话,那就可能存在性能瓶颈。除非还要再基于某个字段做二级分区( 比如 商户ID,那么商户ID也必须是主键的一部分 ) ?

如果时间可以做主键,那可以用联合主键,时间作为二级的range分区

你指的是怎么个联合法 ? 商户ID + 创建时间 ?

我理解你这个还得考虑查询是什么场景吧,我觉得商户id一级hash,订单号二级hash是不是更好点。
用时间分区的话尽管更贴合你的需求4,但在单表的情况下确实是有你说的热点问题。看看别的同学有没有更好的建议

单独用 时间 会有热点问题。
如果使用联合主键,比如 商户ID + 时间(先假设 按天) ,也没法分区。因为商户的数量级在万,时间的数量是 90 左右(3个月),那么算下来就明显超过了 数据库的分区数量限制 65536。

我目前考虑的是,能否按照 商户ID + 用户ID 来分区,因为大多数的查询都是基于这两个维度的,查询上更方便命中单个分区,写入数据也比较离散均匀。只不过,需要自己构造一个特殊的主键ID。查询的时候,也需要特殊处理。