zoukankan      html  css  js  c++  java
  • hive中拉链表

    在有些情况下,为了保持历史的一些状态,需要用拉链表来做,这样做目的在可以保留所有状态的情况下可以节省空间。

    拉链表适用于以下几种情况吧

    数据量有点大,表中某些字段有变化,但是呢变化的频率也不是很高,业务需求呢又需要统计这种变化状态,每天全量一份呢,有点不太现实,

    不仅浪费了存储空间,有时可能业务统计也有点麻烦,这时,拉链表的作用就提现出来了,既节省空间,又满足了需求。

    一般在数仓中通过增加begin_date,en_date来表示,如下例,后两列是start_date和end_date.

    1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20
    1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21
    1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31
    2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20
    2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31
    3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21
    3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31
    4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21
    4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31
    5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31
    

    begin_date表示该条记录的生命周期开始时间,end_date表示该条记录的生命周期结束时间;

    end_date = ‘9999-12-31’表示该条记录目前处于有效状态;

    如果查询当前所有有效的记录,则select * from order_his where dw_end_date = ‘9999-12-31′

    如果查询2016-08-21的历史快照,则select * from order_his where begin_date <= ‘2016-08-21′ and end_date >= ‘2016-08-21’

    再简单介绍一下拉链表的更新:

    假设以天为维度,以每天的最后一个状态为当天的最终状态。

    以一张订单表为例,如下是原始数据,每天的订单状态明细

    1	2016-08-20	2016-08-20	创建
    2	2016-08-20	2016-08-20	创建
    3	2016-08-20	2016-08-20	创建
    1	2016-08-20	2016-08-21	支付
    2	2016-08-20	2016-08-21	完成
    4	2016-08-21	2016-08-21	创建
    1	2016-08-20	2016-08-22	完成
    3	2016-08-20	2016-08-22	支付
    4	2016-08-21	2016-08-22	支付
    5	2016-08-22	2016-08-22	创建
    

    根据拉链表我们希望得到的是

    1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20
    1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21
    1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31
    2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20
    2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31
    3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21
    3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31
    4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21
    4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31
    5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31
    

    可以看出 1,2,3,4每个订单的状态都有,并且也能统计到当前的有效状态。

    本例以hive为例,只考虑到实现,与性能无关

    首先创建表

    CREATE TABLE orders (
    orderid INT,
    createtime STRING,
    modifiedtime STRING,
    status STRING
    ) row format delimited fields terminated by '	' 
    
    
    CREATE TABLE ods_orders_inc (
    orderid INT,
    createtime STRING,
    modifiedtime STRING,
    status STRING
    ) PARTITIONED BY (day STRING)
    row format delimited fields terminated by '	' 
    
    
    CREATE TABLE dw_orders_his (
    orderid INT,
    createtime STRING,
    modifiedtime STRING,
    status STRING,
    dw_start_date STRING,
    dw_end_date STRING
    ) row format delimited fields terminated by '	' ;
    

    首先全量更新,我们先到2016-08-20为止的数据。

    初始化,先把2016-08-20的数据初始化进去

    INSERT overwrite TABLE ods_orders_inc PARTITION (day = '2016-08-20')
    SELECT orderid,createtime,modifiedtime,status
    FROM orders
    WHERE createtime < '2016-08-21' and modifiedtime <'2016-08-21';
    

    刷到dw中

    INSERT overwrite TABLE dw_orders_his
    SELECT orderid,createtime,modifiedtime,status,
    createtime AS dw_start_date,
    '9999-12-31' AS dw_end_date
    FROM ods_orders_inc
    WHERE day = '2016-08-20';
    

    如下结果

    select * from dw_orders_his;
    OK
    1  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31
    2  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31
    3  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31
    

    剩余需要进行增量更新

    INSERT overwrite TABLE ods_orders_inc PARTITION (day = '2016-08-21')
    SELECT orderid,createtime,modifiedtime,status
    FROM orders
    WHERE (createtime = '2016-08-21'  and modifiedtime = '2016-08-21') OR modifiedtime = '2016-08-21';
    
    select * from ods_orders_inc where day='2016-08-21';
    OK
    1  2016-08-20  2016-08-21  支付 2016-08-21
    2  2016-08-20  2016-08-21  完成 2016-08-21
    4  2016-08-21  2016-08-21  创建 2016-08-21
    

    先放到增量表中,然后进行关联到一张临时表中,在插入到新表中

    DROP TABLE IF EXISTS dw_orders_his_tmp;
    CREATE TABLE dw_orders_his_tmp AS 
    SELECT orderid,
    createtime,
    modifiedtime,
    status,
    dw_start_date,
    dw_end_date 
    FROM (
        SELECT a.orderid,
        a.createtime,
        a.modifiedtime,
        a.status,
        a.dw_start_date,
        CASE WHEN b.orderid IS NOT NULL AND a.dw_end_date > '2016-08-21' THEN '2016-08-21' ELSE a.dw_end_date END AS dw_end_date 
        FROM dw_orders_his a 
        left outer join (SELECT * FROM ods_orders_inc WHERE day = '2016-08-21') b 
        ON (a.orderid = b.orderid) 
        UNION ALL 
        SELECT orderid,
        createtime,
        modifiedtime,
        status,
        modifiedtime AS dw_start_date,
        '9999-12-31' AS dw_end_date 
        FROM ods_orders_inc 
        WHERE day = '2016-08-21' 
    ) x 
    ORDER BY orderid,dw_start_date;
    
    INSERT overwrite TABLE dw_orders_his
    SELECT * FROM dw_orders_his_tmp;
    

    在根据上面步骤把2016-08-22号的数据更新进去,最后结果如下

    select * from dw_orders_his;
    OK
    1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20
    1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21
    1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31
    2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20
    2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31
    3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21
    3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31
    4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21
    4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31
    5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31
    

    至此,就得到了我们想要的数据。

  • 相关阅读:
    archlinux .bash_history
    Ubuntu环境下挂载新硬盘
    软碟通 UltraISO U启替代品 Win32DiskImager 无设备 无盘符 无u盘 无优盘 解决方案 之diskpart
    delphi Integer overflow
    MSBuild Tools offline
    delphi synedit免费的拼写检查器dll
    git 自定义命令行
    lua编译
    gcc ar
    Windows Subsystem for Linux (WSL)挂载移动硬盘U盘 卸载 c d 盘
  • 原文地址:https://www.cnblogs.com/wujin/p/6121754.html
Copyright © 2011-2022 走看看