DynamoDB存储员工登录登出信息 免Scan实现工时轮询方案咨询
无Scan操作的DynamoDB工时核查落地方案
核心思路是通过索引设计把需要轮询的员工范围提前收敛,所有查询动作都走精准分区键匹配,从根源上杜绝全表扫描的性能和成本问题。
一、表与索引调整
先补全现有表的键设计和索引,不需要推翻原有字段:
- 原表主键设置:将
员工编号作为分区键,事件发生时间作为排序键。单员工的所有打卡记录会天然按时间有序存储,后续查单个员工当日最新记录时,直接按分区键+时间范围Query即可,单查询RCU消耗极低。 - 新增一个轻量全局二级索引(GSI):
- 分区键为
日期_核查状态拼接字段,排序键为员工编号 - 索引仅投影
员工编号、最新累计工时、最后事件时间三个必要字段,减少存储和读成本 - 字段生成逻辑:每次写入Login/Logout事件时,自动计算两个值:一是事件所属自然日(格式统一为
YYYY/MM/DD),二是当前员工当日的核查状态:如果累计工时<4小时且还没发送过休息提醒,状态记为PENDING;如果已经发过提醒,状态记为NOTIFIED。最终分区键值就是类似2022/6/24_PENDING的字符串。
- 分区键为
二、10分钟轮询逻辑
轮询全程不涉及任何Scan操作:
- 每轮任务触发时,先拼接当日的待核查分区键值,直接Query上述GSI中对应该分区键的所有条目。这一步是严格按分区键的精准查询,不会扫描无关数据。
- 拿到待核查员工列表后,逐个对原表做Query:以
员工编号为分区键,查询条件限定为当日0点到当前时间的事件,取排序最靠后的最新一条记录,拿到实时累计工时:- 如果累计工时≥4小时:立即推送离岗休息提醒,同时将该员工当日最新记录的核查状态更新为
NOTIFIED,更新后该员工条目会自动从GSI的PENDING分区移除,后续轮询不会重复查询、重复发通知。 - 如果累计工时<4小时:不做任何操作,等待下一轮轮询校验即可。
所有读写操作均为DynamoDB的Query、PutItem、UpdateItem标准操作,无全表Scan,完全满足约束要求。
- 如果累计工时≥4小时:立即推送离岗休息提醒,同时将该员工当日最新记录的核查状态更新为
三、边界场景适配
- 连续在岗/间断在岗场景:现有表的
累计工作时长字段本身已经是事件写入时实时计算的累加值,不管员工是连续在岗4小时,还是中途Logout休息多次分段凑够4小时,最新一条事件记录的时长值都是准确的,不需要轮询时临时重算,逻辑和现有样例数据完全兼容。 - 跨天统计场景:轮询任务每次只查当日的
PENDING分区,前一天的待核查分区不会被访问,自然避免跨天工时累加错误。每天0点后新产生的打卡事件会自动归入新一天的分区,不需要额外做全量数据初始化。 - 补卡/漏卡场景:如果有后续补录的历史打卡记录,补录时同步更新该员工当日最新记录的累计时长,如果补录后时长达标且还没发过提醒,直接把核查状态改回
PENDING,下一轮轮询就会覆盖到,不会漏发通知。
四、可选优化
- 可以把阈值判断前置到事件写入环节:每次写入Login/Logout事件时,先判断当前累计时长是否已经到4小时,如果达标直接触发通知,不用等轮询。轮询只需要覆盖「上次事件写入时累计时长3小时,后续员工持续在岗没有新事件写入,时长慢慢累加到4小时」的场景,能大幅降低通知延迟。
- 该设计不存在分区热点问题:GSI的待核查分区按天拆分,且随着轮询推进,已经发过通知的员工会不断移出待核查分区,单分区的数据量会持续下降,不会出现高访问量下的性能瓶颈。
内容的提问来源于stack exchange,提问作者Sukruti
相关产品推荐
相关产品推荐

