Hive有很多种表种类
内部表,外部表,分区表,桶表
全量表、增量表、快照表、切片表和拉链表
- 存量、流量、增量
存量:系统在某一时间点所存有的全部数据量;
流量:是指在某一段时间内流入/出系统的数量;
增量:是指在某一段时间内系统中保有数量的变化;
增量=流入量—流出量
本期期末存量=上期期末存量+本期内增量;
五、拉链表
拉链表专门为了解决在数据仓库中数据变化如何实现数据存储问题,顾名思义,所谓 拉链,就是记录历史。记录 一个事物从开始,一直到当前状态的所有历史变化的信息。
需要条件:
1、需要一张ODS层的用户全量表,需要用它来初始化
2、每日的用户更新表
实现步骤:1、采集增量数据到增量表中
2、将增量表和历史拉链表数据合并,结果写到临时表中
3、将临时表数据覆盖到拉链表中
每日的用户更新表该怎么获取,有以下方式拿到或者间接拿到每日的用户增量:
可以监听Mysql数据的变化,比如说用Canal,最后合并每日的变化,获取到最后的一个状态
假设每天都会获得一份切片数据,可以通过取两天切片数据的不同来作为每日更新表,这种情况下可以对所有的字段先进行concat,再取md5
流水表,有每日的变更流水表
通过etl工具对操作型数据库按照时间字段增量抽取到ods或者数据仓库(每天抽取前一天的数据),形成每天的增量数据(实际中使用最多的情形)。
总结:
1、使用拉链表的时候可以不加t_end_date,即失效日期,但是加上之后,能优化很多查询
2、可以加上当前行状态标识,能快速定位到当前状态
3、在拉链表的设计中可以加一些内容,因为每天保存一个状态,如果在这个状态里面加一个字段,比如如当天修改次数,那么拉链表的作用就会更大
-- 先存临时表,再覆盖
INSERT OVERWRITE TABLE dws.user_his_tmp
SELECT * FROM
(
SELECT A.user_num,
A.mobile,
A.reg_date,
A.t_start_time,
CASE
WHEN A.t_end_time = '9999-12-31' AND B.user_num IS NOT NULL THEN '2017-01-01' -- 原拉链最新数据有更新,更改t_end_time
ELSE A.t_end_time
END AS t_end_time
FROM dws.user_his AS A -- 拉链表
LEFT JOIN ods.user_update AS B -- 今日新增/更新数据
ON A.user_num = B.user_num
UNION
SELECT C.user_num,
C.mobile,
C.reg_date,
'2017-01-02' AS t_start_time,
'9999-12-31' AS t_end_time
FROM ods.user_update AS C -- 今日新增/更新数据
) AS T
拉链表和流水表
流水表存放的是一个用户的变更记录,比如在一张流水表中,一天的数据中,会存放一个用户的每条修改记录,但是在拉链表中只有一条记录。
这是拉链表设计时需要注意的一个粒度问题。我们当然也可以设置的粒度更小一些,一般按天就足够。
查询性能
拉链表当然也会遇到查询性能的问题,比如说我们存放了5年的拉链数据,那么这张表势必会比较大,当查询的时候性能就比较低了,个人认为两个思路来解决:
在一些查询引擎中,我们对 start_date 和 end_date 做索引,这样能提高不少性能。这种方法其实在 Hive 中行不通,因为 Hive 相当于没有索引,不过在其它系统中可以考虑。
保留部分历史数据,比如说我们一张表里面存放全量的拉链表数据,然后再对外暴露一张只提供近 3 个月数据的拉链表。
淘汰机制
关于淘汰机制,其实和性能也是有关系的,一方面是因为所有数据的积累会导致计算越来越慢,另一方面是业务侧其实对历史数据的需求也有一定的优先级的。
因此在设计拉链表的时候可以制定一些数据的淘汰机制。淘汰的数据不一定要删除,比如我们建立两张拉链表,一张拉链表中只保存最新的十条数据,其它的数据会存入一张历史拉链表中。
在使用中还有了一些心得,补充进来:
使用拉链表的时候可以不加 t_end_date,即失效日期,但是加上之后,能优化很多查询。
可以加上当前行状态标识,能快速定位到当前状态。
在拉链表的设计中可以加一些内容,因为我们每天保存一个状态,如果我们在这个状态里面加一个字段,比如如当天修改次数,那么拉链表的作用就会更大。