关于多事务事实表的一点思考
近期在自建数据分析平台的时候,遇到了事实表包含两个业务时间语义的问题,结合数仓事实表建设方面的方法论,整理记录一些自己的想法。
事实表的通常可以划分为如下三类:
- 事务事实表
- 周期快照事实表
- 累积快照事实表
事务事实表又可以分为单事务事实表和多事务事实表。以订单过程为例,一个订单业务过程可以简化为下单和支付两个业务事件,两个事件共享一个订单Id及相应商品的维度信息,但这两个事件可以有不同的业务度量,举例来讲就是下单时有下单金额,支付时有实际支付金额,优惠金额等等。
对于数仓建设来讲,在描述订单业务过程,设计订单事实表模型时,就会面临一个选择:将下单和支付两个业务事件拆开,分别构建单事务事实表还是构建一张多事务事实表。
如果选择构建单事务事实表,优点在于各个事实表的业务语义明确,表分区字段直接采用表达的业务时间即可,方便下游使用方理解,缺点则是会冗余订单维度相关的数据,并且对于同时查询下单和支付度量时,会有表连接的计算开销。
那么构建多事务事实表呢?此时表分区字段就不由具体的业务语义,需要在表中增加相应字段用明确时间语义。举例来讲对于2021-01-26的分区,需要有 '是否当天下单'&'是否当天支付'两个字段来辅助判断分区的时间语义,然后在表中包含下单和支付的度量,对于尚未发生的度量,可以置零。采用这种方案,对于下游使用有一定的理解难度,且度量中可能会有很多0值,但可以避免表连接问题。
上面是在相关数据建设书籍上看到的两种解决方案,两种方案的出发点都是在与每个分区只保存增量的数据,尽量避免存储上的浪费,同时分区数据量减少,也可以提升查询计算的速度,降低计算的开销。
除上述方法之外,如果每天增量的订单数据并不太大,还有第三种方案可以采用(也就是我们现在在用的方案):依然是合并成一个事实表,但是每天的分区都是全量数据,以订单Id作为主键,每条记录保留所有跟订单相关的业务事件的维度&度量信息。也就是说,分区字段就没有任何业务含义,需要下游在使用时根据具体需求去采用相应的时间语义字段。采用这种方案,开发上难度较低,但会有较大的存储浪费,并且每个分区保存全量数据,在计算时也会有较大的资源开销。