场景
假定有个聊天组,组内有成员,成员可以加入和退出(较少发生),此时需求如下
- 查询(历史上)某时间段内(最小单位日)所有存在过的具体成员
- 查询某时间段内新增和退出的具体成员
涉及的表为 group_member
字段:
- member_id = 用户id
- created = 创建时间
方案
传统方案
- 通常简单的方案就是新增两张表,分别 固化数据 + 事件日志存储
- 如果查询某日的组内成员情况,可以每日固化数据
- 对于成员的加入和退出,可以结合当日的 事件日志和前一日的固化数据精确计算结果
- 缺点
- 如果组内成员很多,但是变化较少,则固化方案会导致存储大量的数据,而且会有非常多的重复数据
增量方案
- 除开当前已经存在的现有组内成员表外,新增一个增量事件记录表,记录当日原值和加入与退出的值
事件记录表的成员详情字段结构如下:
{
"originIds": [123123123123,123123123,123123123] , //原本的成员ID
"changeInfos": [
{
"type": "add", //类型为加入
"id": 123123123123 , // 新增的id
},
{
"type": "remove", //类型为退出
"id": 123123123123 , // 移出的id
}
]
}
- 在数据变动时(即成员增加或者退出)则记录
- 如果是当日的,则在原有记录上添加数据
- 如果非当日,比上次记录时间大,则新增一条数据并记录结果值;所以最终存储的结果只有初始值以及后续变动的记录
- 假设原始数据空组,在三日后新增成员1、2, 在8日后成员2退出,且加入成员3; 在表中具有三条记录,分别是创建组后没有成员的初始状态,三日后第一次加入成员的记录,8日后第二次成员变化的记录;
- 如果对时间的精度有要求,这里提供扩展思路
- 对于有统计和查询需求的
- 可以考虑扩展一个事件记录表存储具体的id和事件时间
- 也可以考虑将表的精度调整,从每日调整为更细的力度,但是如果粒度过小,则实质上等同于事件记录表了
- 对于仅仅查看,可以考虑将 changeInfos 中的对象扩展,加入一个发生时间字段即可
- 对于有统计和查询需求的
注意
-
通常查询的范围是包含两端的,考虑到查询的方便,需要插入一条创建前到创建后没有成员的时间段,此时间段内,没有成员
-
查询某日的具体成员情况时,记录表中可能并未直接存储此日期,此时需要查询小于当前日期的首个记录来得到结果
-
查询某一个时间段是,需要注意开始时间的处理