在数据库中,将时间段存储为开始/结束日期,开始日期和时间长度更好吗?

时间:2012-05-01 13:42:57

标签: database database-design

这是一个完全假设的问题:假设我有一个数据库,我需要为用户存储会员资格,这可以持续一段特定的时间(1个月,3个月,6个月,1年等)

让表Memberships具有字段(每个日期存储为unix时间戳)是否更好?

user_id INTstart_date INTend_date INT

或将其存储为:

user_id INTstart_date INTlength INT

无论哪种方式,您都可以查询具有活动成员资格的用户(例如)。对于后一种情况,每次运行查询时都需要执行算术,而前一种情况只需要计算一次结束日期(插入时)。从这个角度来看,似乎前者的设计更好 - 但它有什么缺点吗?是否存在可以通过存储长度来避免的常见问题,这是通过存储日期无法避免的?

此外,unix时间戳是存储时间/日期数据的方式,还是像DATETIME首选的那样?我遇到了两种数据类型(过多的转换)的问题,但通常会解决unix时间戳问题。如果首选像DATETIME这样的东西,这会如何改变我之前设计问题的答案?

6 个答案:

答案 0 :(得分:2)

如果取决于您是否要索引结束日期,而结束日期又取决于您想要查询数据的方式。

如果您这样做,并且如果您的DBMS不支持基于函数的索引或计算列上的索引,那么您唯一的办法就是拥有物理end_date,以便您可以直接为其编制索引。

除此之外,我没有看到太多差异。

顺便说一句,请使用您的DBMS提供的本机日期类型,而不是int。首先,您将实现某种类型的安全措施(如果您尝试读取/写入期望日期的int,则会出现错误),防止您创建不匹配的引用完整性(尽管日期上的FK很少) ,它可以处理时区(取决于DBMS),DBMS通常会为您提供提取日期组件等功能......

答案 1 :(得分:2)

这实际上取决于您针对日期运行的查询类型。如果查询涉及按开始/结束时间或日期范围搜索,则开始/和日期然后肯定是第一个选项。

如果你对统计数据更感兴趣(什么是平均会员期?多少人是一年以上的会员?)那么我会选择第二种选择。

关于过度转换 - 您在哪种语言编程? Java / Ruby使用Joda Time,它简化了日期/时间相关的逻辑。

答案 2 :(得分:1)

我不同意。我会有一个开始和结束日期 - 除了每次执行计算。

答案 3 :(得分:1)

这两种策略功能相同,选择你喜欢的。

答案 4 :(得分:0)

从设计的角度来看,我觉得有一个更好的设计来确定开始日期和成员资格的长度。

结束日期是会员开始日期+持续时间的衍生物。这就是我的想法。

答案 5 :(得分:0)

如果会员资格可以随时间切换,我会建议这个选项:

user_id INT, 
since_date DATE, 
active_membership BIT

active_membership状态随着时间的推移而切换,since_date跟踪发生的时间。此外,如果您拥有有限的允许成员资格长度并且需要跟踪某个用户选择的长度,则可以将其扩展为:

user_id INT, 
since_date DATE, 
active_membership BIT, 
length_id INT

其中length_id将引用可用和允许的成员资格长度的查找表。但请注意,如果可以更改您的会员资格,since_date在这种情况下会变得含糊不清。在这种情况下,您将不得不进一步扩展它:

user_id INT, 
active_membership_since_date DATE, 
active_membership BIT, 
length_since_date DATE,
length_id INT

使用这种方法很容易看出,当两个日期异步变化时,规范化会中断。为了保持这种标准化,你实际上需要6NF。如果您的要求朝这个方向发展,我建议您查看Anchor modeling