【数仓】拉链表 (极限存储) 优化

快照数据, 是数据仓库必不可少的一部分, 尤其是对一些业务来说, 比如贷款风控业务,
常常需要申请贷款前一天的用户画像和相关特征的快照, 作为训练数据集.

最方便的, 比如每一天都存一份全量数据的快照, 容易实现和方便管理.
然而这种方式对于较大的表来说 :

  1. 存储快照数据的成本是巨大的, 尤其在云上精细计费以及行业降本增效的今天.
  2. 当大部分行的数据是没有变更的, 但我们仍旧需要再次保存一份.
  3. 当只有少许行的数据有变更, 但我们仍旧需要全量的计算, 并全量的写入新的快照中去.

当计算和储存的成本太过巨大时, 我们或许应该想想优化的方法了, 而拉链表就是常见的设计.

拉链表

快照表主要多了两个字段: start_dateend_date, 分别代表记录的有效起始时间和结束时间.

例如:

uid name city start_date end_date
1 Adam GZ 2015-01-01 9999-12-31
2 Ben SZ 2015-01-01 2015-01-02
2 Benny SZ 2015-01-02 9999-12-31

假设用 9999-12-31 代表: 这个记录在最新时刻, 它仍然是有效的记录,
而第2条记录的 end_date 代表它在 2015-01-02 之后是无效的,
也就是说, uid=2 的用户在那天之后的 name 叫做 Benny.

查询

如果我们要查询最新的数据, 只需条件 end_date=9999-12-31 即可, 结果将会如下所示:

uid name city start_date end_date
1 Adam GZ 2015-01-01 9999-12-31
2 Benny GZ 2015-01-02 9999-12-31

如果我们要查询 2015-01-01 那天的快照数据, 那么我们需要这些过滤条件:

  • start_date <= 2015-01-01 and end_date > 2015-01-01

查询结果如下:

uid name city start_date end_date
1 Adam GZ 2015-01-01 9999-12-31
2 Ben SZ 2015-01-01 2015-01-02

修改

假设 2015-01-01 那天的最新快照数据如下 :

uid name city start_date end_date
2 Ben SZ 2015-01-01 9999-12-31

假设在 2015-01-02 那天, Ben 修改了 name, 那么当天的快照数据需要:

  1. 把第二行记录的 end_date 改为 2015-01-02,
  2. 插入新的有效记录, 有效 start_date 设置为 2015-01-02 :
uid name city start_date end_date
2 Ben SZ 2015-01-01 2015-01-02
2 Benny GZ 2015-01-02 9999-12-31

问题: 分区

当实际使用快照表时, 我们要如何进行分区呢?

  1. start_dateend_date 进行分区

    假如直接用 start_dateend_date 进行分区, 一年预估也需要 66430 个分区.
    <阿里巴巴大数据实践> 中提到一个做法: 每个月初做一个全量表, 然后当月的每天基于这个全量表
    进行 start_dateend_date 的分区, 这样一年需要的分区可以降到 5232 个.

  2. end_date 进行分类和分区

    当然也有只对 end_date 进行分类和分区的做法, 比如把 end_date 简单分成 latesthistory 两类.
    latest 分区存放 end_date=9999-12-31 的数据, history 分区存放 end_date<今天, 如果 history 分区太大,
    还可以按年份等等维度继续拆分成多个分区, 这种方法的好处就是写入存储和查询时逻辑简单, 分区数量少.

问题: 下游用户易用性

拉链表极限存储, 虽然节省了存储成本, 但在使用上增加了复杂度.
如果有下游用户需要使用到这个拉链表的数据, 那么还是需要对拉链表作一层封装再对外使用的,
比如可以做一个视图, 或者在 SQL 解析中进行 捕捉和转换.

根据我的经验, 有些数据表在大部分业务中, 下游用户用的最多的还是 T-1 的数据,
出于性能和重复计算成本的考虑, 可以每天出一个 T-1 的全量表,
设置相应的生命周期 自动删除, 这样一次写入, 多次读取.
而对于 T-1 之前的数据 再来采用拉链表的查询方式, 因为只有少数业务和少数时间才需要访问历史快照,
当然, 这些都是要根据你的业务上下游的具体情况, 具体分析.

参考

<阿里大数据实践>