1. 什么是时间轴
image.png所有发生的事件,都被按照时间的顺序详细记录,可以通过切换时间追溯到历史上任何一天,展示当时的状态。简单地说,就是给每一条数据更新打上一个时间戳,目的是可追溯。
2. 时间轴的应用
时间轴在人力资源规划模块、招聘与配置模块、培训与发展模块、薪酬管理模块等都有着非常重要的应用。
以薪酬管理模块为例:首先薪酬计算天然就存在时间上的错位,比如我们7月份算的发的是6月份的工资,依据的都是6月份的考勤数据、绩效数据、扣款数据。比如奖金的发放需要依据的是前几个月的数据。年终奖的发放则需要依据全年发生的数据进行计算。
3. 设计时间轴需要考虑的问题
数据量的激增: 好比原来围绕员工有100条数据,升维以后就可能增加几倍到几十倍,这样,保持原有的数据存储和查询性能就需要更加先进的数据处理技术;
对于数据的查询和应用: 特别是涉及到关联性的维护,就需要逐一分辨查询的业务逻辑,是应该使用最新的还是某个具体时间点的数据,需要考虑的业务逻辑自然远远比仅仅记录当前值要复杂;
用户体验: 怎么样能够让用户几乎无感知地自动保存历史、查询引用历史,同时还能在需要时完成必要的交互,保持时间轴数据的完整性和一致性,更加需要精密的设计。
如下图,腾讯使用PeopleSoft(2013年)。除了腾讯,Google、IBM、Yahoo...也在使用SAP或Oracle PeopleSoft的HR系统
image.png4. 实现方案
4.1 定时快照snapshot模式
比如数据每天凌晨定时备份昨天数据
以人事为例,人事一天会多次调整修改员工数据。但是,我们可能只会用到最后一次数据作为当天数据进行核算。
#员工实时表
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键标识',
`employee_no` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '员工工号',
`name` varchar(100) COLLATE utf8mb4_bin DEFAULT '' COMMENT '姓名',
`dept_id` int(11) DEFAULT NULL COMMENT '部门id',
`job_id` int(11) DEFAULT NULL COMMENT '岗位id',
#...员工其他信息
`status`tinyint(2) DEFAULT '0' COMMENT '-1:离职、 0:在职',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_employee_no` (`employee_no`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='员工最新数据表'
凌晨备份当前最新数据
#员工每天备份表
CREATE TABLE `t_user_bk` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键标识',
`employee_no` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '员工工号',
`name` varchar(100) COLLATE utf8mb4_bin DEFAULT '' COMMENT '姓名',
`dept_id` int(11) DEFAULT NULL COMMENT '部门id',
`job_id` int(11) DEFAULT NULL COMMENT '岗位id',
#...员工其他信息
`status` tinyint(2) DEFAULT '0' COMMENT '-1:离职、 0:在职',
`bk_day_no` int(8) DEFAULT NULL COMMENT '备份时间:以天为单位,时间格式: yyyymmdd',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_employee_no_bk_day_no` (`employee_no`,`bk_day_no`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='员工每天备份表'
4.2.2 使用示例
select * from t_user_bk where bk_day_no>20240101 or bk_day_no<20240112
4.2.3 数据维护方法
- 每天备份最新数据
- 异常数据额外清洗
4.2 时间区间模式(SAP使用)
4.2.1 设计原则
- 每个信息类型记录都有开始时间、结束时间
- 每个信息类型都受时间特性类型的控制
时间区间字段
`start_date` datetime DEFAULT NULL COMMENT '开始日期',
`end_date` datetime DEFAULT NULL COMMENT '结束日期',
4.2.2 使用示例
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键标识',
`employee_no` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '员工工号',
`name` varchar(100) COLLATE utf8mb4_bin DEFAULT '' COMMENT '姓名',
`dept_id` int(11) DEFAULT NULL COMMENT '部门id',
`start_date` datetime DEFAULT NULL COMMENT '开始日期',
`end_date` datetime DEFAULT NULL COMMENT '结束日期',
`status` tinyint(2) DEFAULT '0' COMMENT '-1:离职、 0:在职',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_employee_no` (`employee_no`)
) ENGINE=InnoDB AUTO_INCREMENT=130243 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='员工入职离职记录表'
select * from t_user where start_date < '2022-12-31' and end_date < '2023-03-01';
4.2.3 数据维护方法
- 添加最新或未来数据时,需将最后一条数据的结束时间改为新数据开始时间,新数据结束时间改为无穷大
- 插入历史中间数据时,需将有冲突的历史数据开始结束时间做避让,空开新数据的时间区间。如果新数据将历史数据完整包含,历史数据将会被完全覆盖(对于时间特性1类型的数据)
4.3 生效字段模式(Oracle PeopleSoft使用)
4.3.1 设计原则
通过生效日期effect_date、生效状态effect_status、生效序号effect_seq三个简单的字段把系统内的任何一条信息在过去、现在、未来三个截面上构建了连续的数据模型,并且不会影响到数据的使用、展示、和对外提供。
日期类型 | 描述 |
---|---|
当前日期-当前数据 | 当前日期指的是过去最接近今天(含今天)的日期,具有实时性 ,与当前日期对应的数据行即为单签数据。当前日期由有且仅有一个,当前数据也有且仅有一行。 |
历史日期-历史数据 | 小于当前日期的所有日期都是历史日期,与历史日期对应的数据行即为历史数据。显然历史数据可以有多行。 |
将来日期-将来数据 | 大于当前日期的所有日期都是将来日期,与将来日期对应的数据行即为将来数据。显然将来数据可以有多行。 |
通过生效日期,我们可以按时间线准确地维护数据。这样就可以回溯历史信息,同时可以安排将来的事件。
例如,假设今天是2024年4月25日,人事创建一个在2024年5月1日生效的新部门A。但是将来日期,普通员工看不到此记录。
4.3.3 使用示例
CREATE TABLE `t_department` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`dept_code` varchar(30) NOT NULL COMMENT '部门编号',
`parent_dept_code` varchar(30) NOT NULL DEFAULT '' COMMENT '父部门编号',
`effect_date` date NOT NULL COMMENT '生效日期',
`effect_seq` int(11) NOT NULL COMMENT '生效序号',
`dept_name` varchar(30) NOT NULL COMMENT '部门名称',
`leader_id` varchar(20) NOT NULL COMMENT '部门负责人工号',
`status` int(11) NOT NULL COMMENT '部门状态0:失效,1:生效',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1
#查询某个时间所有生效部门
select *
from t_department a
where a.effect_date =
(select max(b.effect_date) from t_department b where b.dept_code = a.dept_code and b.effect_date <= '2024-12-01')
and a.effect_seq =
(select max(c.effect_seq) from t_department c where c.dept_code = a.dept_code and c.effect_date = a.effect_date)
and a.status = 1;
所有数据
查询结果
4.3.3 数据维护方法
- 添加或插入数据时,按期望的生效日期插入,如果当天已存在记录,则按序号添加,或在老序号中间插入,未来数据和历史数据同理。
5.方案对比
方案 | 优点 | 缺点 |
---|---|---|
定时快照snapshot模式 | 能快速查看某一天的所有数据 | 全量数据备份数据冗余过多,处理未来事件比较麻烦,修复数据可能要前后的天数比较多 |
时间区间模式 | sql查询时,只需按所需的日期在开始结束范围内查询,即可确定当时唯一的一组数据 | 因其对每条数据的开始结束时间都有不可重叠的强校验,因此编辑或者修复任何一条数据,都需要同时修改相邻的数据,这增加系统运维的复杂度 |
生效字段模式 | 维护时只需要对应按生效日期添加数据、修改数据、删除数据,可以较方便地对历史回溯数据进行修改。 | sql查询时,有effect_date和effect_seq两个维度需要取max,sql语句取值较复杂,且容易出错。 |
6.参考
事业窗-人力资源数字化的那些黑科技(一):时间轴
得物-人事系统时间轴设计的演化历程
小彭同学-你为什么做不好人力资源系统?(二)——时间轴在HR场景中的应用
Crystal-时间轴是什么?怎么用
网友评论