重复性事件的数据库设计与异常

Posted

技术标签:

【中文标题】重复性事件的数据库设计与异常【英文标题】:Database design for recurring events with exceptions 【发布时间】:2015-08-16 16:55:14 【问题描述】:

我正在构建一个需要存储/管理不同类型事件的系统。为简单起见,我将专注于设计日历(我正在构建一些稍微不同的东西,但日历是一个很好的类比,而且很容易推理)。我想听听可能的数据库/模式设计想法。

问题描述

我有一个包含不同类型事件的日历(为简单起见,假设只有一种类型的事件:任务)。用户可以为特定日期添加新事件、编辑(更改一些细节,如标题或移动到另一个日期)或删除。可以有一次性事件和重复事件(具有不同类型的重复:每 X 天、每月第 15 天、每周星期一;有点像简单的 cron)。当用户移动重复事件时,该事件的所有其他实例都以相同的方式移动(例如:+3 天)。重要部分:重复事件可以有例外。因此,例如,假设我有一个周期性事件 A,它每 7 天重复一次。但是我想将它的日期更改为下周,所以它被分配到星期五而不是星期二,之后它仍然会在星期二发生。移动“父”事件时不应影响此“异常”事件。

此外,每个重复事件都可以有附加信息,仅与 1 个特定实例相关,例如:我有相同的重复事件 A 每 7 天重复一次,我想为本周实例添加一条注释,上面写着“X ",并且我想为下个月的事件 A 添加另一个注释,上面写着“Y” - 这些字段仅对该单个实例可见。

想法

具有定期、一次性事件的系统非常简单,因此我不会讨论这个问题,只关注重复性事件。

1. 一种可能的解决方案是类似于 OOP 的解决方案:我可以有一个带有 start_dateend_date 等字段的 Event“类”(可以是 null) ,recurrence_type(类似于枚举,可能值为EVERY_X_DAYSDAY_OF_WEEKDAY_OF_MONTH)和recurrence_value(比如7)。当用户添加新的重复事件时,我只是在数据库中创建这样的Event。当用户想要更改此事件的 1 次发生时,我将新条目添加到类型/类 MovedEvent 的数据库中,该条目从 Event “继承”,具有不同的日期,并具有指向 @987654341 的附加字段 related_to @(或UUID,如果你愿意的话)与它相关的Event。但同时,我需要跟踪所有MovedEvents(否则我将在同一周显示2个事件),所以我需要有一个数组moved_events IDs 那一点致所有MovedEvents。 缺点:每次我想显示日历时都需要获取Event 并从moved_events 中选择所有事件,如果我有很多移动的事件,这不是最佳选择。

2. 另一个想法是将每个事件存储为单独的记录。 IMO 这是一个糟糕的主意,但我只是提到它是因为它是一种可能性。 缺点:每次我想编辑主要事件时(例如:我想将事件从“每 7 天”更改为“每 9 天”),我都需要更改事件。不过,“例外”(更改单个实例)更容易。

SQL/NoSQL?比例细节

我在我的项目中使用 PostgreSQL,但我对 NoSQL 数据库有基本的了解,如果它们更适合此类问题,我可以使用它。

规模:假设我有 5000 个用户,每个用户平均每周有 150 个事件,其中 40% 可能是“例外”。因此,我想将这个系统设计得更高效。

类似问题和其他资源

我刚刚开始阅读 Martin Fowler 的“日历的重复事件”(http://martinfowler.com/apsupp/recurring.pdf),但我不确定它是否适用于我的问题,如果适用,如何根据本文档设计数据库模式(建议欢迎)。

有类似的问题,但我没有看到任何提及“异常”(更改 1 个事件实例而不影响其他事件实例),但也许有人会发现这些链接很有用:

Design question: How would you design a recurring event system?

Optimal design for a Database with recurring event

Design option for 'recurring tasks'

Calendar Recurring/Repeating Events - Best Storage Method

What is the best way to represent "Recurring Events" in database?

抱歉,问题很长,我想很好地描述问题。然而,我觉得这很混乱,所以如果你有其他问题,我会很乐意提供更多细节。同样,我想听听可能的数据库/模式设计理念以及任何其他建议。谢谢!

【问题讨论】:

嘿,您可以分享一下您是如何最终实施这个的经验或一些实施技巧。 您好,我也在处理这个问题。我决定对每次重复发生都采用单独的事件条目的直截了当的解决方案。我的事件系统对每个事件的发生分别具有 RSVP、支付和 cmets 等活动,并且每个事件发生必须有它自己的唯一事件 ID、最高优先级。仅此一项就使我的选择变得容易,我必须分别存储每个事件。从好的方面来说,我的用户群活动一次只发生几个月,所以我可以制定一个自动到期规则(例如最多 3 个月),这将使数据库处理时间保持可控。 【参考方案1】:

使用iCalendar RRules 和 ExDates

如果是重复事件,只需存储该事件的开始/结束日期时间以及 RRules 和 ExDates。

使用物化视图预先计算即将发生的实际事件,例如未来 30 天或 365 天。

当您使用 Postgres 时,您可以在 pg 函数中使用现有的 python、perl 或 javascript RRule 库(例如dateutil)来根据 rrules 和 exdates 计算未来事件

更新:查看 pg_rrule 扩展:https://github.com/petropavel13/pg_rrule

【讨论】:

ExRules 在 RFC 5455(链接的那个)中已弃用。 ExDates 现在用于创建 RRules 的例外。但是,截至本评论,pg_rrule 不支持 ExDate。 There's an open issue on this 四年后我看到了你的评论,伙计,我希望我在两周前找到它。

以上是关于重复性事件的数据库设计与异常的主要内容,如果未能解决你的问题,请参考以下文章

20172303 2017-2018-2 《程序设计与数据结构》第8周学习总结

分布式事务解决:可靠消息的最终一致性方案-消息重复发送问题与业务接口的幂等性设计

20172326 《程序设计与数据结构》第九周学习总结

数据库设计规范

# 20172318 2017-2018-2 《程序设计与数据结构》第10周学习总结

Redis | 第6章 事件与客户端《Redis设计与实现》