1. 程式人生 > >拉鏈表流水表

拉鏈表流水表

每天 sel 版權 pid not part IV creat 生命周期

  1. 1. 全量表:每天的所有的最新狀態的數據,
  2. 2. 增量表:每天的新增數據,增量數據是上次導出之後的新數據。
  3. 3. 拉鏈表:維護歷史狀態,以及最新狀態數據的一種表,拉鏈表根據拉鏈粒度的不同,實際上相當於快照,只不過做了優化,去除了一部分不變的記錄而已,通過拉鏈表可以很方便的還原出拉鏈時點的客戶記錄。
  4. 4. 流水表: 對於表的每一個修改都會記錄,可以用於反映實際記錄的變更。
  5. 拉鏈表通常是對賬戶信息的歷史變動進行處理保留的結果,流水表是每天的交易形成的歷史;
  6. 流水表用於統計業務相關情況,拉鏈表用於統計賬戶及客戶的情況
  7. 數據倉庫之拉鏈表(原理、設計以及在Hive中的實現)
  8. 在有些情況下,為了保持歷史的一些狀態,需要用拉鏈表來做,這樣做目的在可以保留所有狀態的情況下可以節省空間。
  9. 拉鏈表適用於以下幾種情況吧
  10. 數據量有點大,表中某些字段有變化,但是呢變化的頻率也不是很高,業務需求呢又需要統計這種變化狀態,每天全量一份呢,有點不太現實,
  11. 不僅浪費了存儲空間,有時可能業務統計也有點麻煩,這時,拉鏈表的作用就提現出來了,既節省空間,又滿足了需求。
  12. 一般在數倉中通過增加begin_date,en_date來表示,如下例,後兩列是start_date和end_date.
  13. 1 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-20
  14. 1 2016-08-20 2016-08-21 支付 2016-08-21 2016-08-21
  15. 1 2016-08-20 2016-08-22 完成 2016-08-22 9999-12-31
  16. 2 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-20
  17. 2 2016-08-20 2016-08-21 完成 2016-08-21 9999-12-31
  18. 3 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-21
  19. 3 2016-08-20 2016-08-22 支付 2016-08-22 9999-12-31
  20. 4 2016-08-21 2016-08-21 創建 2016-08-21 2016-08-21
  21. 4 2016-08-21 2016-08-22 支付 2016-08-22 9999-12-31
  22. 5 2016-08-22 2016-08-22 創建 2016-08-22 9999-12-31
  23. begin_date表示該條記錄的生命周期開始時間,end_date表示該條記錄的生命周期結束時間;
  24. end_date = ‘9999-12-31’表示該條記錄目前處於有效狀態;
  25. 如果查詢當前所有有效的記錄,則select * from order_his where dw_end_date = ‘9999-12-31′
  26. 如果查詢2016-08-21的歷史快照,則select * from order_his where begin_date <= ‘2016-08-21′ and end_date >= ‘2016-08-21’
  27. 再簡單介紹一下拉鏈表的更新:
  28. 假設以天為維度,以每天的最後一個狀態為當天的最終狀態。
  29. 以一張訂單表為例,如下是原始數據,每天的訂單狀態明細
  30. 1 2016-08-20 2016-08-20 創建
  31. 2 2016-08-20 2016-08-20 創建
  32. 3 2016-08-20 2016-08-20 創建
  33. 1 2016-08-20 2016-08-21 支付
  34. 2 2016-08-20 2016-08-21 完成
  35. 4 2016-08-21 2016-08-21 創建
  36. 1 2016-08-20 2016-08-22 完成
  37. 3 2016-08-20 2016-08-22 支付
  38. 4 2016-08-21 2016-08-22 支付
  39. 5 2016-08-22 2016-08-22 創建
  40. 根據拉鏈表我們希望得到的是
  41. 1 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-20
  42. 1 2016-08-20 2016-08-21 支付 2016-08-21 2016-08-21
  43. 1 2016-08-20 2016-08-22 完成 2016-08-22 9999-12-31
  44. 2 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-20
  45. 2 2016-08-20 2016-08-21 完成 2016-08-21 9999-12-31
  46. 3 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-21
  47. 3 2016-08-20 2016-08-22 支付 2016-08-22 9999-12-31
  48. 4 2016-08-21 2016-08-21 創建 2016-08-21 2016-08-21
  49. 4 2016-08-21 2016-08-22 支付 2016-08-22 9999-12-31
  50. 5 2016-08-22 2016-08-22 創建 2016-08-22 9999-12-31
  51. 可以看出 1,2,3,4每個訂單的狀態都有,並且也能統計到當前的有效狀態。
  52. 本例以hive為例,只考慮到實現,與性能無關
  53. 首先創建表
  54. CREATE TABLE orders (
  55. orderid INT,
  56. createtime STRING,
  57. modifiedtime STRING,
  58. status STRING
  59. ) row format delimited fields terminated by ‘\t‘
  60. CREATE TABLE ods_orders_inc (
  61. orderid INT,
  62. createtime STRING,
  63. modifiedtime STRING,
  64. status STRING
  65. ) PARTITIONED BY (day STRING)
  66. row format delimited fields terminated by ‘\t‘
  67. CREATE TABLE dw_orders_his (
  68. orderid INT,
  69. createtime STRING,
  70. modifiedtime STRING,
  71. status STRING,
  72. dw_start_date STRING,
  73. dw_end_date STRING
  74. ) row format delimited fields terminated by ‘\t‘ ;
  75. 首先全量更新,我們先到2016-08-20為止的數據。
  76. 初始化,先把2016-08-20的數據初始化進去
  77. INSERT overwrite TABLE ods_orders_inc PARTITION (day = ‘2016-08-20‘)
  78. SELECT orderid,createtime,modifiedtime,status
  79. FROM orders
  80. WHERE createtime < ‘2016-08-21‘ and modifiedtime <‘2016-08-21‘;
  81. 刷到dw中
  82. INSERT overwrite TABLE dw_orders_his
  83. SELECT orderid,createtime,modifiedtime,status,
  84. createtime AS dw_start_date,
  85. ‘9999-12-31‘ AS dw_end_date
  86. FROM ods_orders_inc
  87. WHERE day = ‘2016-08-20‘;
  88. 如下結果
  89. select * from dw_orders_his;
  90. OK
  91. 1 2016-08-20 2016-08-20 創建 2016-08-20 9999-12-31
  92. 2 2016-08-20 2016-08-20 創建 2016-08-20 9999-12-31
  93. 3 2016-08-20 2016-08-20 創建 2016-08-20 9999-12-31
  94. 剩余需要進行增量更新
  95. INSERT overwrite TABLE ods_orders_inc PARTITION (day = ‘2016-08-21‘)
  96. SELECT orderid,createtime,modifiedtime,status
  97. FROM orders
  98. WHERE (createtime = ‘2016-08-21‘ and modifiedtime = ‘2016-08-21‘) OR modifiedtime = ‘2016-08-21‘;
  99. select * from ods_orders_inc where day=‘2016-08-21‘;
  100. OK
  101. 1 2016-08-20 2016-08-21 支付 2016-08-21
  102. 2 2016-08-20 2016-08-21 完成 2016-08-21
  103. 4 2016-08-21 2016-08-21 創建 2016-08-21
  104. 先放到增量表中,然後進行關聯到一張臨時表中,在插入到新表中
  105. DROP TABLE IF EXISTS dw_orders_his_tmp;
  106. CREATE TABLE dw_orders_his_tmp AS
  107. SELECT orderid,
  108. createtime,
  109. modifiedtime,
  110. status,
  111. dw_start_date,
  112. dw_end_date
  113. FROM (
  114. SELECT a.orderid,
  115. a.createtime,
  116. a.modifiedtime,
  117. a.status,
  118. a.dw_start_date,
  119. 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
  120. FROM dw_orders_his a
  121. left outer join (SELECT * FROM ods_orders_inc WHERE day = ‘2016-08-21‘) b
  122. ON (a.orderid = b.orderid)
  123. UNION ALL
  124. SELECT orderid,
  125. createtime,
  126. modifiedtime,
  127. status,
  128. modifiedtime AS dw_start_date,
  129. ‘9999-12-31‘ AS dw_end_date
  130. FROM ods_orders_inc
  131. WHERE day = ‘2016-08-21‘
  132. ) x
  133. ORDER BY orderid,dw_start_date;
  134. INSERT overwrite TABLE dw_orders_his
  135. SELECT * FROM dw_orders_his_tmp;
  136. 在根據上面步驟把2016-08-22號的數據更新進去,最後結果如下
  137. select * from dw_orders_his;
  138. OK
  139. 1 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-20
  140. 1 2016-08-20 2016-08-21 支付 2016-08-21 2016-08-21
  141. 1 2016-08-20 2016-08-22 完成 2016-08-22 9999-12-31
  142. 2 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-20
  143. 2 2016-08-20 2016-08-21 完成 2016-08-21 9999-12-31
  144. 3 2016-08-20 2016-08-20 創建 2016-08-20 2016-08-21
  145. 3 2016-08-20 2016-08-22 支付 2016-08-22 9999-12-31
  146. 4 2016-08-21 2016-08-21 創建 2016-08-21 2016-08-21
  147. 4 2016-08-21 2016-08-22 支付 2016-08-22 9999-12-31
  148. 5 2016-08-22 2016-08-22 創建 2016-08-22 9999-12-31
  149. 至此,就得到了我們想要的數據。

值得註意的是,訂單表中數據同一天有多次狀態更新,應以每天的最後一個狀態為當天的最終狀態。比如一天之內訂單狀態創建,支付,完成都有,應拉取最終的狀態進行拉練表更新,否則後面的數據可能就會出現異常,比如

[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 版權聲明:本文為博主原創文章,未經博主允許隨機轉載。 https://blog.csdn.net/mtj66/article/details/78019370

拉鏈表流水表