假如我们有一个账号account表,我们需要在hive中存储(数据是从线上mysql读取binlog同步来的,是有明细变化的)

account表结构:account_id, username, followers_count, modified_at

我们经常使用的存储方式有快照表和流水表。快照表就是以时间为粒度(比如天),生成每个时间的全量数据快照;流水表则是记录数据的每一条具体的改变。

现在有一个需求:需要记录账号的历史变更情况

快照表实现

这里以天为粒度,对每天账号最终的状态进行存储即可。

在hive中,以天为分区存储,我们需要访问某天的历史状态,直接指定分区即可访问

-- 访问20190801时某个账号的状态
select * from account_snapshot where ds = "20190801" and account_id = xxx

快照表的缺点是:当单表的数据量比较大时,每天存储全量的快照,会导致不必要的资源开支

流水表实现

流水表记录数据的每一条变化,来一条插入一条

这种存储方法对数据的使用者不太友好

-- 查询20190801时某个账号的状态
select * from (select *, row_number over(partition by account_id order by modified_at desc) as rofrom account where modified_at <= "2019-08-02 00:00:00" and account_id = xxx
) where ro = 1  

以上的两种方式,多多少少都存在问题,接下来介绍拉链表的使用

拉链表

拉链表是维护历史状态、以及最新状态的一种方式。

拉链表对快照表进行了优化,根据拉链粒度(一般为时间)的不同,去除了在粒度范围内不变的数据。

拉链表可以维护两个时间(start_time, end_time),来标识当前记录是否还有效,以及更好的定位历史数据

实现前提:

首先要有某一时刻的全量数据,作为起始表

其次要有流水表或者快照表两者其一,作为变化的依据

实现:
-- 原始数据
create table account(account int ,username varchar,followers_count int ,modified_at timestamp
)-- 创建拉链表
create table account_zip(account int ,username varchar,followers_count int ,modified_at timestamp ,start_time timestamp, -- 记录的有效起始时间end_time timestamp, -- 记录的有效结束时间
)

今天是8.1,我们从7.31号的数据开始记录

首先我们将7.31号的数据导入我们的拉链表中
insert into account_zip
select *, "2019-07-31 00:00:00" as start_time ,"9999-12-31 00:00:00" as end_time
from
account ;

这里的start_time指的是这条记录是在7.31改变生效的,end_time是指这条记录在9999-12-31前是有效的。导入拉链表后,表内的记录如下所示,

接下来,我们在8.1的时候,对账号进行修改和新增


左边是7.31的数据,右边是8.1的数据

我们可以看到8.1进行了一条记录的修改(修改mwf的followers_account)和一条记录的新增(新增account_id为5的用户)

针对修改来说:

在拉链中已经存在mwf的信息,8.1对他进行修改,

我们可以将之前那条记录的end_time修改为8.1,表示他在8.1之后失效了

然后将8.1的这次操作写入拉链表,他的start_time为8.1,end_time为9999-12-31

针对新增来说:

我们直接将它写入拉链表,start_time为8.1,end_time为9999-12-31

8.1过后,我们的拉链表变为了如下版本:

以上我们就实现了一个拉链表

查询记录
  • 查询当前的有效记录
select * from account_zip where end_time = "9999-12-31 00:00:00"
  • 如查询2019-07-31时的历史快照
-- 在7.31号前开始生效,且在7.31号当天时还没有失效, 此处通过两个时间刚好限定了范围
select * from account_zip
where start_time <= "2019-07-31 00:00:00" and end_time >= "2019-07-31 00:00:00"

基于快照表生成拉链表

insert into account_zip_tmp
-- 联合两个表,写入临时的拉链表中
select * from (-- 改变原有拉链表中 失效的数据-- 这里用到了md5来比较数据是否相同select bak.account_id,bak.username ,bak.followers_count  ,bak.modified_at, bak.start_timecase when bak.end_time = "9999-12-31 00:00:00" and  md5(concat(coalesce(bak.username, 'NULL'),coalesce(bak.followers_count, 'NULL'),coalesce(bak.modified_at, 'NULL'))) != md5(concat(coalesce(new.username, 'NULL'),coalesce(new.followers_count, 'NULL'),coalesce(new.modified_at, 'NULL'))) then "2019-07-31 00:00:00" else bak.end_timeend as end_time from account_zip as bak left join (select * from account_snapshot where ds = "20190801") as new on bak.account_id = new.account_idunion -- 写入修改或新增的数据select a.account_id,a.username ,a.followers_count  ,a.modified_at, "2019-07-31 00:00:00" as start_time, "9999-12-31 00:00:00" as end_timefrom (   select * from account_snapshot where ds = "20190801") as a left join (select *from account_zipwhere end_time = "9999-12-31 00:00:00") on a.account_id = b.account_idwhere md5(concat(coalesce(a.username, 'NULL'),coalesce(a.followers_count, 'NULL'),coalesce(a.modified_at, 'NULL'))) != md5(concat(coalesce(b.username, 'NULL'),coalesce(b.followers_count, 'NULL'),coalesce(b.modified_at, 'NULL')))
);-- 将临时拉链表写回拉链表
insert overwrite table account_zip
select * from account_zip_tmp
参考
https://www.jianshu.com/p/799252156379

实践出真知 !

数据仓库历史数据存储 - 拉链表相关推荐

  1. 数据仓库历史数据存储-拉链表

    拉链表 拉链表是维护历史状态.以及最新状态的一种方式. 拉链表对快照表进行了优化,根据拉链粒度(一般为时间)的不同,去除了在粒度范围内不变的数据. 拉链表可以维护两个时间(start_time, en ...

  2. 数据仓库中历史拉链表的更新方法

    原文地址:http://lxw1234.com/archives/2015/08/473.htm 这里简单介绍一下这种历史拉链表的更新方法. 本文中假设: 数据仓库中订单历史表的刷新频率为一天,当天更 ...

  3. hql取满足条件最新一条记录_数据仓库怎么做拉链表记录数据变化情况,看看这篇文章 就明白了...

    小文老师给你讲解数据仓库的ETL拉链算法,通过这篇文档,让你快速了解数据拉链. 一 首先我们先来看下,什么是拉链?在数据仓库中,拉链就是记录数据在某一时间区间内的状态以及数据在某一时间点上的数据变化的 ...

  4. 【clickhouse】数据仓库中的拉链表(Clickhouse 实现)

    文章目录 1.概述 在 Clickhouse 中实现拉链表 一. 每日的用户更新表: 二. ods 层的 user 表: ods 层的 user_update 表 拉链表: 拉链表和流水表: 查询性能 ...

  5. Hive数据仓库中历史拉链表实践

    数据准备 在mysql中创建测试表orders CREATE TABLE `orders` (`orderid` int(11) NOT NULL AUTO_INCREMENT,`status` va ...

  6. 数仓--拉链表(原理、设计以及在Hive中的实现)

    拉链表 什么是拉链表? 谈到拉链表就不得不谈SCD(缓慢变化维问题) 缓慢变化维怎么解决?(粗看有五种) 保留初始值(不让改) 改写属性值 ==增加维度新行== 增加维度新列 使用历史表 举一个具体的 ...

  7. 拉链表(SCD2)的操作

    什么时候使用拉链表? 当数据存在有变更的情况时,可以采用渐变维(SCD)模型来解决.这里推荐使用SCD2拉链 表.拉链表既可以反应数据的历史状态,又能在最大程度上节省存储. 拉链表的实现需要在原始字段 ...

  8. Hive数仓拉链表详解

    文章目录 1. 初始化数据 1.1 建表 1.2 加载数据 1.3 验证同步数据 2. 新增2020-06-21分区数据 3. 加载数据到拉链表 4. 新增2020-06-22分区数据 5. 再次加载 ...

  9. 数据仓库数据模型之:极限存储--历史拉链表

    摘要: 在数据仓库的数据模型设计过程中,经常会遇到文内所提到的这样的需求.而历史拉链表,既能满足对历史数据的需求,又能很大程度的节省存储资源. 在数据仓库的数据模型设计过程中,经常会遇到这样的需求: ...

最新文章

  1. SDN中的Heavy-Hitter测量文献阅读
  2. 使用devenv/MSBuild在命令行编译单个project
  3. 计算机二级考试题停车收费,计算机二级考试真题-Excel-停车场调整收费标准
  4. 月工资5000元,如何快速积累30万?
  5. leetcode738. 单调递增的数字(贪心)
  6. java的min函数_Java语言实现包含min函数的栈
  7. python分类算法的应用_Python使用sklearn库实现的各种分类算法简单应用小结
  8. 探究Lucene计算权重的过程
  9. 内存性能测试---stream benchmark 的使用
  10. 【北大知识图谱】知识图谱的关键技术及其智能应用
  11. UART协议TTL电平接口高性能低功耗SI4463无线透传通信模块
  12. GDS中如何加logo
  13. 数据结构实验二——队列(银行叫号系统)
  14. H323端口开放一览表
  15. 44.git仓库账号或着密码修改之后需要重新配置SSH公钥
  16. Google Earth Engine学习笔记(一)
  17. 【Bootstrap-学习小结】
  18. ElementUI-分页-自定义文字-共计-跳至
  19. 程序员应该掌握的选择思维模式?
  20. 32位驱动模式写保护开关

热门文章

  1. 智力答题源码php,php儿童智力测评系统
  2. 朱松纯领衔、北大清华超强联合,开启「通用人工智能实验班」
  3. css flash布局_跳过简介-CSS3是新的Flash
  4. Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entr
  5. Android学习-使用WebView在app上显示网页
  6. nginx 按天分割日志
  7. 2018蓝桥模拟赛 天上的星星
  8. java tapestry_Java Web 框架 Tapestry
  9. 打印机显示检查打印服务器,win10系统打开打印机提示再次检查打印机的名称怎么办...
  10. 【面试被虐】如何只用2GB内存从20亿,40亿,80亿个整数中找到出现次数最多的数?