历史拉链表

  1. 1. 全量表:每天的所有的最新状态的数据。
  2.   
  3. 2. 增量表:每天的新增数据,增量数据是上次导出之后的新数据。
  4.   
  5. 3. 拉链表:维护历史状态,以及最新状态数据的一种表,拉链表根据拉链粒度的不同,实际上相当于快照,只不过做了优化,去除了一部分不变的记录而已,通过拉链表可以很方便的还原出拉链时点的客户记录。
  6.   
  7. 4. 流水表: 对于表的每一个修改都会记录,可以用于反映实际记录的变更。   
  8.   
  9. 拉链表通常是对账户信息的历史变动进行处理保留的结果流水表是每天的交易形成的历史;  
  10. 流水表用于统计业务相关情况,拉链表用于统计账户及客户的情况  
  11. 数据仓库之拉链表(原理、设计以及在Hive中的实现)  
  12.   
  13. 在有些情况下,为了保持历史的一些状态,需要用拉链表来做,这样做目的在可以保留所有状态的情况下可以节省空间。  
  14.   
  15. 拉链表适用于以下几种情况吧  
  16.   
  17. 数据量有点大,表中某些字段有变化,但是呢变化的频率也不是很高,业务需求呢又需要统计这种变化状态,每天全量一份呢,有点不太现实,  
  18.   
  19. 不仅浪费了存储空间,有时可能业务统计也有点麻烦,这时,拉链表的作用就提现出来了,既节省空间,又满足了需求。  
  20.   
  21. 一般在数仓中通过增加begin_date,en_date来表示,如下例,后两列是start_date和end_date.  
  22.    
  23. 1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  24. 1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21  
  25. 1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31  
  26. 2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  27. 2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31  
  28. 3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21  
  29. 3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31  
  30. 4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21  
  31. 4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31  
  32. 5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  33. begin_date表示该条记录的生命周期开始时间,end_date表示该条记录的生命周期结束时间;  
  34.   
  35. end_date = ‘9999-12-31’表示该条记录目前处于有效状态;  
  36.   
  37. 如果查询当前所有有效的记录,则select * from order_his where dw_end_date = ‘9999-12-31′  
  38.   
  39. 如果查询2016-08-21的历史快照,则select * from order_his where begin_date <= ‘2016-08-21′ and end_date >= ‘2016-08-21’  
  40.   
  41. 再简单介绍一下拉链表的更新:  
  42.   
  43. 假设以天为维度,以每天的最后一个状态为当天的最终状态。  
  44.   
  45. 以一张订单表为例,如下是原始数据,每天的订单状态明细  
  46.   
  47. 1   2016-08-20  2016-08-20  创建  
  48. 2   2016-08-20  2016-08-20  创建  
  49. 3   2016-08-20  2016-08-20  创建  
  50. 1   2016-08-20  2016-08-21  支付  
  51. 2   2016-08-20  2016-08-21  完成  
  52. 4   2016-08-21  2016-08-21  创建  
  53. 1   2016-08-20  2016-08-22  完成  
  54. 3   2016-08-20  2016-08-22  支付  
  55. 4   2016-08-21  2016-08-22  支付  
  56. 5   2016-08-22  2016-08-22  创建  
  57. 根据拉链表我们希望得到的是  
  58.   
  59.    
  60. 1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  61. 1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21  
  62. 1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31  
  63. 2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  64. 2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31  
  65. 3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21  
  66. 3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31  
  67. 4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21  
  68. 4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31  
  69. 5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  70. 可以看出 1,2,3,4每个订单的状态都有,并且也能统计到当前的有效状态。  
  71.   
  72. 本例以hive为例,只考虑到实现,与性能无关  
  73.   
  74. 首先创建表  
  75.    
  76. CREATE TABLE orders (  
  77. orderid INT,  
  78. createtime STRING,  
  79. modifiedtime STRING,  
  80. status STRING  
  81. ) row format delimited fields terminated by '\t'  
  82.    
  83.    
  84. CREATE TABLE ods_orders_inc (  
  85. orderid INT,  
  86. createtime STRING,  
  87. modifiedtime STRING,  
  88. status STRING  
  89. ) PARTITIONED BY (day STRING)  
  90. row format delimited fields terminated by '\t'  
  91.    
  92.    
  93. CREATE TABLE dw_orders_his (  
  94. orderid INT,  
  95. createtime STRING,  
  96. modifiedtime STRING,  
  97. status STRING,  
  98. dw_start_date STRING,  
  99. dw_end_date STRING  
  100. ) row format delimited fields terminated by '\t' ;  
  101. 首先全量更新,我们先到2016-08-20为止的数据。  
  102.   
  103. 初始化,先把2016-08-20的数据初始化进去  
  104.    
  105. INSERT overwrite TABLE ods_orders_inc PARTITION (day = '2016-08-20')  
  106. SELECT orderid,createtime,modifiedtime,status  
  107. FROM orders  
  108. WHERE createtime < '2016-08-21' and modifiedtime <'2016-08-21';  
  109. 刷到dw中  
  110.    
  111. INSERT overwrite TABLE dw_orders_his  
  112. SELECT orderid,createtime,modifiedtime,status,  
  113. createtime AS dw_start_date,  
  114. '9999-12-31' AS dw_end_date  
  115. FROM ods_orders_inc  
  116. WHERE day = '2016-08-20';  
  117.   
  118. 如下结果  
  119.    
  120. select * from dw_orders_his;  
  121. OK  
  122. 1  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31  
  123. 2  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31  
  124. 3  2016-08-20  2016-08-20  创建 2016-08-20  9999-12-31  
  125. 剩余需要进行增量更新  
  126.   
  127.    
  128. INSERT overwrite TABLE ods_orders_inc PARTITION (day = '2016-08-21')  
  129. SELECT orderid,createtime,modifiedtime,status  
  130. FROM orders  
  131. WHERE (createtime = '2016-08-21'  and modifiedtime = '2016-08-21'OR modifiedtime = '2016-08-21';  
  132.    
  133. select * from ods_orders_inc where day='2016-08-21';  
  134. OK  
  135. 1  2016-08-20  2016-08-21  支付 2016-08-21  
  136. 2  2016-08-20  2016-08-21  完成 2016-08-21  
  137. 4  2016-08-21  2016-08-21  创建 2016-08-21  
  138. 先放到增量表中,然后进行关联到一张临时表中,在插入到新表中  
  139.   
  140.    
  141. DROP TABLE IF EXISTS dw_orders_his_tmp;  
  142. CREATE TABLE dw_orders_his_tmp AS  
  143. SELECT orderid,  
  144. createtime,  
  145. modifiedtime,  
  146. status,  
  147. dw_start_date,  
  148. dw_end_date  
  149. FROM (  
  150.     SELECT a.orderid,  
  151.     a.createtime,  
  152.     a.modifiedtime,  
  153.     a.status,  
  154.     a.dw_start_date,  
  155.     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  
  156.     FROM dw_orders_his a  
  157.     left outer join (SELECT * FROM ods_orders_inc WHERE day = '2016-08-21') b  
  158.     ON (a.orderid = b.orderid)  
  159.     UNION ALL  
  160.     SELECT orderid,  
  161.     createtime,  
  162.     modifiedtime,  
  163.     status,  
  164.     modifiedtime AS dw_start_date,  
  165.     '9999-12-31' AS dw_end_date  
  166.     FROM ods_orders_inc  
  167.     WHERE day = '2016-08-21'  
  168. ) x  
  169. ORDER BY orderid,dw_start_date;  
  170.    
  171. INSERT overwrite TABLE dw_orders_his  
  172. SELECT * FROM dw_orders_his_tmp;  
  173. 在根据上面步骤把2016-08-22号的数据更新进去,最后结果如下  
  174.   
  175.    
  176. select * from dw_orders_his;  
  177. OK  
  178. 1  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  179. 1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21  
  180. 1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31  
  181. 2  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-20  
  182. 2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31  
  183. 3  2016-08-20  2016-08-20  创建 2016-08-20  2016-08-21  
  184. 3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31  
  185. 4  2016-08-21  2016-08-21  创建 2016-08-21  2016-08-21  
  186. 4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31  
  187. 5  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  188. 至此,就得到了我们想要的数据。  


值得注意的是,订单表中数据同一天有多次状态更新,应以每天的最后一个状态为当天的最终状态。比如一天之内订单状态创建,支付,完成都有,应拉取最终的状态进行拉练表更新,否则后面的数据可能就会出现异常,比如

[sql] view plain copy
  1. 6  2016-08-22  2016-08-22  创建 2016-08-22  9999-12-31  
  2. 6  2016-08-22  2016-08-22  支付 2016-08-22  9999-12-31  
  3. 6  2016-08-22  2016-08-22  完成 2016-08-22  9999-12-31  


http://www.cnblogs.com/wujin/p/6121754.html

http://www.jianshu.com/p/799252156379

http://lxw1234.com/archives/2015/04/20.htm

猜你喜欢

转载自blog.csdn.net/qq_41797451/article/details/80333335