greenplum 历史拉链表

3.1 历史拉链表

数据仓库定义:是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。

历史拉链表:一种数据模型,主要是针对数据仓库设计中表存储数据的方式而定义的。它记录了一个事物从开始到当前状态的所有变化的信息。避免了按每一天存储所有记录造成的海量存储问题,同事也是处理缓慢变化数据的一种常见方式。

3.1.1 应用场景描述

企业有5000万会员信息,每天有20万会员资料变更,每天要保存一份数据快照以记录历史变化。那么一年数据条数为2x365x5000w是365亿条。如果用历史拉链表那么,每天只需向历史表中添加新增和变化的数据量,每天不过20万条。

3.1.2 原理及步骤

拉链表中的每一条数据都有一个生效日期(dw_beg_date)和失效日期(dw_end_date)。

member_fatdt0:表示member的事实表,其中P30001231保存的是最新数据,每个分区保留的都是历史已失效的数据。
member_delta:当天的数据库变更数据,action字段表示该数据为新增(I)、更新(U)、删除(D)。

3.3.3 表结构

  1. 拉链表(member_facdt0)结构
create table public.member_fatdt0
(
	Member_id	varchar(64)   --会员ID
	,phoneno 	varchar(20)	  --电话号码
	,dw_beg_date date	      --生效日期
	,dw_end_date date         --失效日期
	,dtype       char(1)      --类型(历史数据、当前数据)
	,dw_status   char(1)      --数据操作类型(I,D,U)
	,dw_ins_date date         --数据仓库插入日期
) with(appendonly=true,compresslevel=5)
distributed by(member_id)
partition by range(dw_end_date)
(
partition p20111201 start (date '2011-12-01') inclusive,
partition p20111202 start (date '2011-12-02') inclusive,
partition p20111203 start (date '2011-12-03') inclusive,
partition p20111204 start (date '2011-12-04') inclusive,
partition p20111205 start (date '2011-12-05') inclusive,
partition p20111206 start (date '2011-12-06') inclusive,
partition p20111207 start (date '2011-12-07') inclusive,
partition p20111231 start (date '2011-12-31') inclusive
end (date '3001-01-01') exclusive
);
  1. 增量表(member_delta)结构
Create table public.member_delta
(
	Member_id		varchar(64)			--会员id
	,phoneno		varchar(20)			--电话号码
	,action			char(1)				--类型(新增,删除,更新)
	,dw_ins_date 	date				--数据仓库插入日期
) with(appendonly=true,compresslevel=5)
distributed by(member_id);
  1. 临时表0(member_tmp0)结构
Create table public.member_tmp0
(
	Member_id			varchar(64)			--会员ID
	,phoneno			varchar(20)			--电话号码
	,dw_beg_date		date				--生效日期
	,dw_end_date		date				--失效日期
	,dtype				char(1)				--类型(历史数据、当前数据)
	,dw_status			char(1)				--数据操作类型(I,D,U)
	,dw_ins_date		date				--数据仓库插入日期
) with(appendonly=true,compresslevel=5)
distributed by(member_id)
partition by list(dtype)
(
	partition phis values ('H'),
	partition pcur values ('C'),
	default partition other
);
  1. 临时表1(member_tmp1)结构
Create table public.member_tmp1
(
	Member_id			varchar(64)			--会员ID
	,phoneno			varchar(20)			--电话号码
	,dw_beg_date		date				--生效日期
	,dw_end_date		date				--失效日期
	,dtype				char(1)				--类型(历史数据、当前数据)
	,dw_status			char(1)				--数据操作类型(I,D,U)
	,dw_ins_date		date				--数据仓库插入日期
) with(appendonly=true,compresslevel=5)
distributed by(member_id);

3.1.5 数据加载

greenplum数据加载方式包括:SQL的insert、copy、外部表、gpload、web external table几种方式。

  1. insert
    加载方式效率最差,只适合加载极少量数据
insert into public.member_delta values('mem006','13100000006','I',date'2011-12-03');
insert into public.member_delta values('mem002','13100000002','D',date'2011-12-03');
insert into public.member_delta values('mem003','13100000003','U',date'2011-12-03');
  1. copy
    copy这种数据加载方式源于PostgreSQL,数据需要通过Master节点,无法实现并行高效数据加载。
copy public.member_fatdt0_1_prt_p30001231 from '/home/gpadmin/member_his_init.dat' with delimiter ',';
  1. 外部表
    首先,启动gpfdist服务:
nohup gpfdist -d /home/gpadmin/data/ -p 8888 -l /home/gpadmin/data/gpfdist.log &

其次,创建外部表:

drop external table if exists public.member_ext;
create external table public.member_ext
(
	Member_id			varchar(64)
	,phoneno			varchar(20)
	,action				char(1)
	,dw_ins_date		date
)
location ('gpfdist://localhost:8888/member_delta.dat')
format 'text'
(delimiter ',' null as '' escape 'off')
encoding 'gb18030'
log errors into member_err segment reject limit 2 rows;

最后,执行数据装载:

Insert into public.member_delta select * from public.member_ext;
  1. gpload
    gpload是对外部表的一层封装,编写yam文件用于说明输入输出,之后执行gpload命令。

  2. 可执行外部表
    不用启动gpfdist服务,其中基于操作系统命令读取数据文件的方式和普通外部表类似。下面的外部表只在Master上执行:

drop external web table if exists public.member_ext;
create external web table public.member_ext
(
	Member_id			varchar(64)
	,phoneno			varchar(20)
	,action				char(1)
	dw_ins_date			date
)
execute 'cat /home/gpadmin/data/member_delta.dat' on master
format 'text'
(delimiter ',' null as '' escape 'off')
encoding 'gb18030'
;

清空member_delta表并插入数据:

truncate table public.member_delta;
Insert into public.member_delta select * from public.member_ext;

3.1.6 数据刷新

  1. 拉链表刷新
    step1:对事实表中的最新数据(分区P30001231)与member_delta表中的更新、删除数据进行左外连接,关联上则说明该数据发生过变更,需要将该数据的失效时间更新为当天,并插入到member_tmp0表中的历史数据分区中,关联不上则说明没有发生过变更,需要将该数据插入到member_tmp0表的当前数据分区中。Greenplum会根据dtype的数据自动选择对应的分区。

初始全量数据为2011-12-01号,在12月3号刷新12月2号增量数据,代码如下:

truncate table public.member_tmp0;
-- 清理临时表
insert into public.member_tmp0
(
	Member_id
	,phoneno
	,dw_beg_date
	,dw_end_date
	,dtype
	,dw_status
	,dw_ins_date
)
select a.Member_id
		,a.phoneno
		,a.dw_beg_date
		,case when b.Member_id is null then a.dw_end_date
		else date'2011-12-02'
		end as dw_end_date
		,case when b.Member_id is null then 'C'
		else 'H'
		end as dtype
		,case when b.Member_id is null then a.dw_status
		else b.action 
		end as dw_status
		,date'2011-12-03'
from	public.member_fatdt0
left join public.member_delta
on		a.Member_id = b.Member_id
and 	b.action IN('D','U')
where a.dw_beg_date <= cast('2011-12-02' as date)-1
and   a.dw_end_date>cast('2011-12-02' as date) -1;

step2: 将member_delta的新增、更新数据插入到member_tmp0表的当前数据分区中。

insert into public.member_tmp0
(
	Member_id,
	phoneno,
	dw_beg_date,
	dw_end_date,
	dtype,
	dw_status,
	dw_ins_date
)
select Member_id,
	   phoneno,
	   cast('2011-12-02' as date),
	   cast('3000-12-31' as date),
	   'C',
	   action,
	   cast('2011-12-03' as date)
from public.member_delta
where action in('I','U');

step3: 将member_fatdt0表中的对应分区(P20121201)与member_tmp0表的历史数据分区交换。

Truncate table public.member_tmp1;
alter table public.member_tmp0 exchange partition for('H') with table public.member_tmp1;
alter table public.member_fatdt0 exchange partition for('2011-12-02') with table public.member_tmp1;

step4: 将member_fatdt0表中对应的当前数据分区(p30001231)与member_tmp0表的当前数据分区交换

alter table public.member_tmp0 exchange partition for('C') with table public.member_tmp1;
alter table public.member_fatdt0 exchange partition for('3000-12-31') with table public.member_tmp1;

3.1.7 分区裁剪

只对某个分区的数据进行查询

3.1.8 数据导出

GP再处理大数据量数据导出时常用的方式主要有并行导出(可写外部表)和非并行导出(COPY),copy命令比较简单。下面是可写外部表数据导出方式,通过gpfdist可写外部表将数据导出至文件服务器
1)创建可写外部表

create writable external table member_tmp1_upload
(like member_tmp1)
location ('gpfdist://localhost:8080/member_tmp1.dat')
format 'TEXT' (DELIMITER ',')
DISTRIBUTED BY (member_id);

2)执行数据导出

insert into member_tmp1_upload select * from member_tmp1;

3)验证生成的文件

less member_tmp1.dat

你可能感兴趣的:(数据仓库,数据库,hive)