数据仓库定义:是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。
历史拉链表:一种数据模型,主要是针对数据仓库设计中表存储数据的方式而定义的。它记录了一个事物从开始到当前状态的所有变化的信息。避免了按每一天存储所有记录造成的海量存储问题,同事也是处理缓慢变化数据的一种常见方式。
企业有5000万会员信息,每天有20万会员资料变更,每天要保存一份数据快照以记录历史变化。那么一年数据条数为2x365x5000w是365亿条。如果用历史拉链表那么,每天只需向历史表中添加新增和变化的数据量,每天不过20万条。
拉链表中的每一条数据都有一个生效日期(dw_beg_date)和失效日期(dw_end_date)。
member_fatdt0:表示member的事实表,其中P30001231保存的是最新数据,每个分区保留的都是历史已失效的数据。
member_delta:当天的数据库变更数据,action字段表示该数据为新增(I)、更新(U)、删除(D)。
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
);
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);
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
);
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);
greenplum数据加载方式包括:SQL的insert、copy、外部表、gpload、web external table几种方式。
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');
copy public.member_fatdt0_1_prt_p30001231 from '/home/gpadmin/member_his_init.dat' with delimiter ',';
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;
gpload
gpload是对外部表的一层封装,编写yam文件用于说明输入输出,之后执行gpload命令。
可执行外部表
不用启动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;
初始全量数据为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;
只对某个分区的数据进行查询
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