拉链表实现及使用

拉链表实现及使用一、概念历史拉链表,就是记录一个事务从开始一直到当前状态的所有变化的信息,拉链表可以避免按每一天存储所有记录造成的海量存储问题,同时也是处理缓慢变化数据的一种常见方式。假设企业拥有1000万的会员信息,每天有20万的会员资料变更,我们需要记录所有会议的历史变化记录,并至少保留两年,该怎么办?储存两年就是2x365x1000万=7300000000(70亿),如果储存…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、概念

历史拉链表,就是记录一个事务从开始一直到当前状态的所有变化的信息,拉链表可以避免按每一天存储所有记录造成的海量存储问题,同时也是处理缓慢变化数据的一种常见方式。

 

假设企业拥有1000万的会员信息,每天有20万的会员资料变更,我们需要记录所有会议的历史变化记录,并至少保留两年,该怎么办?

储存两年就是 2 x 365 x 1000万 = 7300000000(70亿),如果储存更长时间,则无法估算需要的存储。而用拉链表存储,每日只向表中新增和变化的数据量,每日不过20万条,

储存2年也只需要 2 x 365 * 200000 = 146000000 (1.46以)存储空间。

 

二、案例设计

–创建用户信息的原始表

drop table t_userinfo_src;

create table t_userinfo_src(

    user_id int,

    user_name character varying,

    user_no integer,

    phone_no character varying,

    create_date date,

    update_date date

) distribute by hash(user_id);

 

–创建目标拉链表

drop table t_userinfo_zipper;

create table t_userinfo_zipper(

    user_id int,

    user_name character varying,

    user_no integer,

    phone_no character varying,

    effective_date date,

    invalid_date date

) distribute by hash(user_id);

 

2019年11月12日 新增了两个用户,

则这两条记录的生效时间为当天,由于到 2019年11月12日 为止,这两条记录还没有被修改过,所以失效时间为无穷大,

这里设置为数据库中的最大值(3000-12-31),数据如下:

insert into t_userinfo_src(user_id,user_name,user_no,phone_no,create_date,update_date) 

values(1001,’se7en.shi’,’110′,’13000000001′,’2019-11-12′,’2019-11-12′),

(1002,’eleven’,’120′,’13000000002′,’2019-11-12′,’2019-11-12′),

(1003,’rose’,’120′,’13000000003′,’2019-11-12′,’2019-11-12′);

 

postgres=> select * from t_userinfo_src;

 user_id | user_name | user_no |  phone_no   |     create_date     |     update_date

———+———–+———+————-+———————+———————

    1002 | eleven    |     120 | 13000000002 | 2019-11-12 00:00:00 | 2019-11-12 00:00:00

    1001 | se7en.shi |     110 | 13000000001 | 2019-11-12 00:00:00 | 2019-11-12 00:00:00

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2019-11-12 00:00:00

(3 rows)

 

–执行函数,传入今天的时间,处理昨天的数据

select * from fn_userinfo_zipper(‘2019-11-13’);

 

–查看拉链表的数据

postgres=> select * from t_userinfo_zipper;

 user_id | user_name | user_no |  phone_no   |   effective_date    |    invalid_date

———+———–+———+————-+———————+———————

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00

    1001 | se7en.shi |     110 | 13000000001 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00   

    1002 | eleven    |     120 | 13000000002 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00

(3 rows)

 

第二天(2019-11-13),

用户 1001 被删除,

用户 1002 的电话号码被修改成 13000000004 。

为了保留历史状态,用户 1001 的失效时间被修改成 2019-11-12,用户 1002 则变成两条记录,

新增1004用户数据。

 

–原始表的操作为

delete from t_userinfo_src where user_id=1001;

update t_userinfo_src set phone_no=’13000000004′,update_date=’2019-11-13′ where user_id=1002;

insert into t_userinfo_src(user_id,user_name,user_no,phone_no,create_date,update_date) 

values(1004,’jack’,’110′,’13000000005′,’2019-11-13′,’2019-11-13′);

 

–查看原始表数据

postgres=> select * from t_userinfo_src;

 user_id | user_name | user_no |  phone_no   |     create_date     |     update_date

———+———–+———+————-+———————+———————

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2019-11-12 00:00:00

    1004 | jack      |     110 | 13000000005 | 2019-11-13 00:00:00 | 2019-11-13 00:00:00

    1002 | eleven    |     120 | 13000000004 | 2019-11-12 00:00:00 | 2019-11-13 00:00:00

 

postgres=> select * from t_userinfo_zipper;

 user_id | user_name | user_no |  phone_no   |   effective_date    |    invalid_date

———+———–+———+————-+———————+———————

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00   –拉链表中,14号执行后,应该被新增 

    1001 | se7en.shi |     110 | 13000000001 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00   –拉链表中,14号执行后,应该被删除

    1002 | eleven    |     120 | 13000000002 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00   –拉链表中,14号执行后,应该被标记为无效,无效时间是2019-11-13 00:00:00

 

–执行函数

select * from fn_userinfo_zipper(‘2019-11-14’);

 

–执行函数后查看数据

postgres=> select * from t_userinfo_src;

 user_id | user_name | user_no |  phone_no   |     create_date     |     update_date

———+———–+———+————-+———————+———————

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2019-11-12 00:00:00

    1004 | jack      |     110 | 13000000005 | 2019-11-13 00:00:00 | 2019-11-13 00:00:00

    1002 | eleven    |     120 | 13000000004 | 2019-11-12 00:00:00 | 2019-11-13 00:00:00

(3 rows)

 

postgres=> select * from t_userinfo_zipper;

 user_id | user_name | user_no |  phone_no   |   effective_date    |    invalid_date

———+———–+———+————-+———————+———————

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00   

    1001 | se7en.shi |     110 | 13000000001 | 2019-11-12 00:00:00 | 2019-11-13 00:00:00   –被标记为删除,invalid_date为2019-11-13 00:00:00

    1004 | jack      |     110 | 13000000005 | 2019-11-13 00:00:00 | 2999-12-31 00:00:00   –新增数据

    1002 | eleven    |     120 | 13000000002 | 2019-11-12 00:00:00 | 2019-11-13 00:00:00   –被标记为无效 

    1002 | eleven    |     120 | 13000000004 | 2019-11-13 00:00:00 | 2999-12-31 00:00:00   –更新后的数据

(5 rows)

 

–拉链表的使用

1,如果要查询最新的数据,那么只要查询失效时间为 2999-12-31 的数据即可

postgres=> select * from t_userinfo_zipper where invalid_date=’2999-12-31′;

 user_id | user_name | user_no |  phone_no   |   effective_date    |    invalid_date

———+———–+———+————-+———————+———————

    1004 | jack      |     110 | 13000000005 | 2019-11-13 00:00:00 | 2999-12-31 00:00:00

    1003 | rose      |     120 | 13000000003 | 2019-11-12 00:00:00 | 2999-12-31 00:00:00

    1002 | eleven    |     120 | 13000000004 | 2019-11-13 00:00:00 | 2999-12-31 00:00:00

 

1,如果要查询 2019年11月12号 的历史数据,则筛选生效时间 <= 2019-11-13 并且失效时间 > 2019-11-13 的数据即可;

postgres=> select * from t_userinfo_zipper where invalid_date<=’2019-11-13′ and invalid_date >=’2019-11-13′;

 user_id | user_name | user_no |  phone_no   |   effective_date    |    invalid_date

———+———–+———+————-+———————+———————

    1002 | eleven    |     120 | 13000000002 | 2019-11-12 00:00:00 | 2019-11-13 00:00:00

    1001 | se7en.shi |     110 | 13000000001 | 2019-11-12 00:00:00 | 2019-11-13 00:00:00

(2 rows)

 

–实现函数如下

create or replace function fn_userinfo_zipper(IN cur_date text)

    returns void

as $$

/*

本功能是将原数据表中 新增数据、修改、删除记录到拉链表中

invalid_date 设定为 2999-12-31

 

本函数传入值为时间,具体为今天执行昨天的数据,参数为 (to_date(cur_date,’yyyy-mm-dd’) – 1)

总体逻辑如下

–1.目标表中没有此主键的,确定为新增  –  新增

–2,捕获原表被删除的数据,并更新拉链表被删除数据的失效时间

–3 捕获被修改的内容,将其置为无效

–3.1 闭链:目标表中有此主键的记录,状态值不同,更新结束日期为当天

–3.2 开链:目标表中新增一条修改的数据,更新结束日期为无穷大

 

@author: se7en.shi

@date: 2019-11-13

*/

declare

begin

–1.目标表中没有此主键的,确定为新增  –  新增

insert into t_userinfo_zipper(user_id,user_name,user_no,phone_no,effective_date,invalid_date)

select a.user_id,a.user_name,a.user_no,a.phone_no,a.create_date,to_date(‘2999-12-31′,’yyyy-mm-dd’) as invalid_date

from t_userinfo_src a

where a.create_date=(to_date(cur_date,’yyyy-mm-dd’) – 1)

and not exists(

select 1 from t_userinfo_zipper b

where a.user_id=b.user_id);

raise notice ‘finish new increasing …’;

 

–2,捕获原表被删除的数据,并更新拉链表被删除数据的失效时间

update t_userinfo_zipper a set invalid_date=(to_date(cur_date,’yyyy-mm-dd’)-1)

where not EXISTS(

    select 1 from t_userinfo_src b 

    where a.user_id=b.user_id

);

raise notice ‘finish delete data capture …’;

 

–3 捕获被修改的内容,将其置为无效

–3.1 闭链:目标表中有此主键的记录,状态值不同,更新结束日期为当天

update t_userinfo_zipper a set invalid_date=(to_date(cur_date,’yyyy-mm-dd’)-1)

where a.invalid_date=to_date(‘2999-12-31′,’yyyy-mm-dd’)

and exists(

    select 1 from t_userinfo_src b 

    where a.user_id=b.user_id and b.create_date < (to_date(cur_date,’yyyy-mm-dd’)-1)

    and (b.user_name<>a.user_name or b.user_no<>a.user_no or b.phone_no<>a.phone_no)

);

raise notice ‘finish modifyed data capture lable invalid…’;

 

–3.2 开链:目标表中新增一条修改的数据,更新结束日期为无穷大

insert into t_userinfo_zipper(user_id,user_name,user_no,phone_no,effective_date,invalid_date)

select a.user_id,a.user_name,a.user_no,a.phone_no,(to_date(cur_date,’yyyy-mm-dd’) – 1) as effective_date,to_date(‘2999-12-31′,’yyyy-mm-dd’) as invalid_date

from t_userinfo_src a

where a.create_date<=(to_date(cur_date,’yyyy-mm-dd’) – 1)

and exists(

    select 1 from (

        select user_id,effective_date,max(invalid_date) as invalid_date

        from t_userinfo_zipper 

        group by user_id,effective_date ) b

        where a.user_id=b.user_id

        and a.create_date=b.effective_date

        and b.invalid_date <=  (to_date(cur_date,’yyyy-mm-dd’) – 1)

);

raise notice ‘finish modifyed data capture new insert’;

end;

$$ language plpgsql;

 

各种数据库迁移到PostgreSQL及PG维保、紧急救援及商业服务,请扫码联系。

———————————————————-

          个人微信                                  

个人微信

创作不易,如果对你的工作有帮助,打赏小费,以资鼓励吧

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181259.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • -2147467259数据库操作错误!

    -2147467259数据库操作错误!没事说搭建个asp的网站,下载了个aspcms源码系统。搭建出现的主要问题是:登录后台的时候提示:-2147467259数据库操作错误!怎么解决?搜索了一下,有些说得是那么个意思,可是我的电脑环境也有些特殊情况。(比如:文件夹属性中没有“安全”选项卡)下面整理下:-21474672

  • sql smallint与int_datetime数据类型

    sql smallint与int_datetime数据类型使用整数数据的精确数字数据类型。bigint数值范围从-2^63(-9223372036854775808)到2^63-1(9223372036854775807)的整型数据(所有数字)。存储大小为8个字节。int数值范围从-2^31(-2,147,483,648)到2^31-1(2,147,483,647)的整型数据(所有数字)。存储大小为4个字节。int的SQL-92同义字为integer。smallint数值范围从-2^15(-32,76

  • p2p在线直播流(何为流媒体)

    看到网上一些吹牛P2P低延时的文章,觉得不是很靠谱,抽空调研了一下这个问题。P2P低延时的几个方向:   方法一:通过直接采集并编码多媒体帧,将多媒体帧切分成1KB大小的数据颗粒,采用push策略的进行小包传输,提高传输效率,减小传输延时;          具体参见:http://www.google.com/patents/CN101945129A?cl

  • 网页下载文件错误_python安装报错

    网页下载文件错误_python安装报错如图,使用webdriver的过程中出现如下提示,代码正常,下载地址正常,在正常浏览器中也可以成功下载文件但是模拟浏览器却无法成功获取文件;尝试了开发模式启动、禁用或启用js等等,都没有成功,快要放弃chrome准备改选firefox的时候,看到了一个解决方法:此方法只针对一种情况有效:如果你在下载路径前加了r,转义了原始字符串,如下那么,去掉“r”试一下成功了如有问题请留言…

  • 一些免费的代理服务器「建议收藏」

    一些免费的代理服务器「建议收藏」http://www.cnproxy.com/proxy1.html12.24.45.100:80   24.25.26.82:8024.25.26.128:8024.25.26.131:8024.25.26.136:8024.29.138.66:8024.119.115.228:8062.41.85.113:8063.236.6.200:8064.26.

  • java堆栈详解

    java堆栈详解java虚拟机栈栈是线程私有,他的生命周期和线程的相同。用于存储局部变量,操作数栈,动态链接,方法出口等。他会抛出两种异常,stackoverflowerror异常和outofmemoryerror异常。java虚拟机堆堆是线程共有的一块内存区域,在虚拟机启动时创建,为了存放对象实例。java堆是垃圾收集器管理的主要区域,因此很多时候被称为“GC堆”。java堆可以处于物理上不连续的内

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号