数据漂移问题出现的背景
我们通常构建数仓的ODS层时,会考虑按照某个时间戳将数据切分后分区存储。
ODS表中常出现的时间戳分为四个类型:
- 源表中标识数据记录更新的时间戳字段,modified_time。
- 源表中标识源库日志记录更新的时间戳字段,log_time。
- 源表中记录具体业务过程发生的时间戳字段,proc_time。
- 标识数据从源表抽取到数仓的时间戳字段,extract_time。
理想情况下,上述几类时间戳记录的时间一致,这样无论使用哪个时间戳作为ODS表分区的依据,同一调度周期内的业务发生时间都位于同一个分区,不存在数据漂移。
但是,生产上通常会出现如下问题,这个问题可能导致这几类时间不一致:
- 数据抽取需要时间,所以extract_time往往晚于其他三个时间。
- 前台业务系统手工修改数据时,并没有同步更新modified_time。
- 由于应用系统的压力,导致modified_time和log_time晚于proc_time。
这样,我们在ODS中使用各种时间戳切分数据时会面临各种问题:
为了便于分析,我们假设统计周期是天,即ODS表每天数据存到一个分区。
1. 如果根据extract_time切分数据。
由于extract_time往往晚于proc_time,导致proc_time发生在某天末尾的少部分记录对应的extract_time会在第二天开头,这时如果按extract_time会导致当天proc_time对应的记录存在当天和第二天两个分区中。
2. 如果根据modified_time切分数据。
可能某业务过程开始发生在11:59:59,而业务过程结束,在数据库生成数据的时间在第二天,也就是说proc_time在11:59:59的记录,对应的modified_time记录的时间在第二天。这时如果按照modified_time分区,会导致proc_time在11:59:59的记录存在第二天的分区内。
3. 根据log_time切分数据。
由于log_time是由应用系统日志程序记录的,当生成环境发生网络或者系统压力时,log_time会晚于proc_time。这时如果按照log_time分区,会发生和上述一样的问题。
4. 如果直接根据proc_time切分数据。
如果该事实表只记录了一个业务过程,是可行的。
但是如果事实表记录了多个业务过程,只用某一个业务过程的proc_time做为分区时间,那么当天分区必定会遗漏其他业务过程的数据。
如何处理数据漂移
最常用的处理方法是在ODS表每个时间分区中向前、后多冗余一些数据,保障数据只多不少,具体应用的时候可以让下游的表根据自身业务需要用不同的proc_time去做筛选处理。
当然这种方式对累积快照事实表是有一些统计风险的,例如一个订单是当天支付的,但是第二天凌晨申请退款关闭了,那么当这个订单离线同步到ODS时,记录该订单的记录只会保留最终的订单状态。那么统计当天订单数量时会出现错误。