数仓--DW--Hadoop数仓实践Case-13-周期快照事实表

周期快照概述

  • 周期快照事实表中的每行汇总了发生在某一标准周期, 如一天、 一周或一月的多个度量。 其粒度是周期性的时间段, 而不是单个事务。周期快照事实表通常包含许多数据的总计, 因为任何与事实表时间范围一致的记录都会被包含在内。在这些事实表中, 外键的密度是均匀的, 因为即使周期内没有活动发生, 通常也会在事实表中为每个维度插入包含0或空值的行。
  • 周期快照在库存管理和人力资源系统中有比较广泛的应用。 商店的库存优化水平对连锁企业的获利将产生巨大影响。 需要确保正确的产品处于正确的商店中, 在正确的时间尽量减少出现脱销的情况, 并减少总的库存管理费用。 零售商希望通过产品和商店分析每天保有商品的库存水平。 在这个场景下, 我们希望分析的业务过程是零售商店库存的每日周期快照。 在人力资源管理系统中, 除了为员工建立档案外, 还希望获得员工状态的例行报告, 包括员工数量、 支付的工资、 假期天数、 新增员工数量、离职员工数量, 晋升人员数量等。 这时需要建立一个每月员工统计周期快照。
  • 周期快照是在一个给定的时间对事实表进行一段时期的总计。 有些数据仓库用户, 尤其是业务管理者或者运营部门, 经常要看某个特定时间点的汇总数据。 下面在示例数据仓库中创建一个月销售订单周期快照, 用于按产品统计每个月总的销售订单金额和产品销售数量。

修改数仓模式

  • 需求是要按产品统计每个月的销售金额和销售数量。 单从功能上看, 此数据能够从事务事实表中直接查询得到。 例如, 要取得2019年3月的销售数据, 可以使用以下的语句查询:
-- 查询以月为单位的数据,以2019.03
select
    b.month_key, a.product_key, sum(order_amount), sum(order_quantity)
from
    dw.sale_order_fact a,
    source.source_month_dim b,
    source.source_order_date_dim d
where
    a.order_date_sk = d.order_date_sk
and
    b.month= d.month
and
    b.year= d.year
and
    b.month= 3
and
    b.year= 2019
group by
    b.month_key, a.product_key ;
  • 只要将年、 月参数传递给这条查询语句,就可以获得任何年月的统计数据。 但即便是在如此简单的场景下,我们仍然需要建立独立的周期快照事实表。 事务事实表的数据量都会很大,如果每当需要月销售统计数据时, 都从最细粒度的事实表查询, 那么性能将会差到不堪忍受的程度。 再者,月统计数据往往只是下一步数据分析的输入信息,有时把更复杂的逻辑放到一个单一的查询语句中效率会更差。 因此, 好的做法是将事务型事实表作为一个基石事实数据, 以此为基础, 向上逐层建立需要的快照事实表。
  • 下图的模式显示了一个名为dw.month_end_sale_order_fact的周期快照事实表。


    月度销售周期快照表.PNG
  • 新的周期快照事实表中有两个度量值, 即month_order_amount和month_order_quantity。 这两个值是不能加到dw.sale_order_fact表中的, 原因是, sale_order_fact表和新的度量值有不同的时间属性, 也即数据的粒度不同。
  • dw.sale_order_fact表包含的是单一事务记录。 新的度量值包含的是每月的汇总数据。 销售周期快照是一个普通的引用两个维度的事实表。 月份维度表包含以月为粒度的销售周期描述符。 产品代理键对应有效的产品维度行, 也就是给定报告月的最后一天对应的产品代理键, 以保证月末报表是对当前产品信息的准确描述。 快照中的事实包含每月的数字度量和计数, 它们是可加的。 该快照事实表使用ORC存储格式。

创建周期快照表

脚本如下:

-- 创建周期快照表
create table
    dw.month_end_sale_order_fact
(
order_month_sk int comment'order month SK',
product_sk int comment'product SK',
month_order_amount decimal(10,2) comment'month order amount',
month_order_quantity int comment'month order quantity'
)
clustered by(order_month_sk) into 8 buckets
stored as
orc tblproperties ('transactional'='true');

周期快照装载脚本

  • 建立dw.month_end_sale_order_fact表后, 现在需要向表中装载数据。 实际装载时, 月销售周期快照事实表的数据源是已有的销售订单事务事实表, 而并没有关联产品维度表。 之所以可以这样做, 是因为总是先处理事务事实表, 再处理周期快照事实表, 并且事务事实表中的产品代理键就是当时有效的产品描述。 这样做还有一个好处是, 不必要非在1号装载上月的数据, 这点在后面修改工作流时会详细说明。 month_sum.sql脚本文件用于装载月销售订单周期快照事实表, 该文件内容如下。
    month_sum.sql

-- 装载周期快照表
-- 上月某日期
set hivevar:pre_month_date = add_months(current_date,-1);
-- 幂等操作, 先删除上月数据
delete from
    dw.month_end_sale_order_fact
where
    month_end_sale_order_fact.order_month_sk 
in
(
    select month_sk from
        month_dim
    where 
    month= month(${hivevar:pre_month_date})
    and 
    year= year(${hivevar:pre_month_date})
);
-- 插入上个月销售汇总数据
insert into 
    dw.month_end_sale_order_fact
select 
(
    b.month_key,
    nvl(a.product_sk,'N/A'),
    sum(order_amonut),
    sum(order_quantity)
)
from
    source.order_date_dim d
left join
    dw.sale_order_fact a
on
    d.order_date_key=a.order_date_sk
inner join
    source.source_month_dim b
on
    b.month=d.month 
and
    b.year=d.year
and 
    b.month=month(${hivevar:pre_month_date})
and
    b.year=year(${hivevar:pre_month_date})
group by
    b.month_key,a.product_sk
;
  • 前面曾经提到过, 周期快照表的外键密度是均匀的, 因此这里使用外连接关联订单日期维度和事务事实表。 即使上个月没有任何销售记录, 周期快照中仍然会有一行记录。 在这种情况下, 周期快照记录中只有月份代理键, 而产品代理键的值为预定义的‘N/A’, 这可以通过nvl函数实现, 度量则为空值。 严格地说产品维度表中应该增
    加‘N/A’这样一行表示没有对应产品时的默认值。
  • 在实际生成中,是需要建立对应的hive分区的。不能将所有的数据都加入到一张表中。
  • 每个月给定的任何一天, 在每天销售订单定期装载执行完后, 执行month_sum.sql脚本, 装载上个月的销售订单汇总数据。需要修改Azkaban中的任务调度流

周期快照表总结

  • 周期快照粒度表示一种常规性的重复的度量或度量集合, 比如每月报表。 这类事实表通常包括一个单一日期列, 表示一个周期。 周期快照的事实必须满足粒度需求,仅描述适合于所定义周期的时间范围的度量。 周期快照是一种常见的事实表类型, 通常用于表示账户余额、 每月财务报表以及库存余额等。 周期快照的周期通常是天、 周或月等。
  • 周期快照具有与事务粒度事实表类似的装载特性, 插入数据的过程类似。 传统上, 周期快照在适当的时期结束时将被装载, 就像示例演示的那样。 还有常见的一种做
    法是, 滚动式地添加周期快照记录。 在满足以下两个条件时, 往往采用滚动式数据装载。 一是事务数据量非常大, 以至于装载一个月的快照需要很长时间; 二是快照的度量是可增加的。 例如, 我们可以建立每日销售周期快照, 数据从事务事实表汇总而来, 然后月快照数据从每日快照汇总。 这样能够把一个大的查询分散到每一天进行。

你可能感兴趣的:(数仓--DW--Hadoop数仓实践Case-13-周期快照事实表)