【问题标题】:How would you design this DB?你将如何设计这个数据库?
【发布时间】:2009-11-02 10:43:00
【问题描述】:

我们正在推出一个网站(付费订阅),注册过程包括输入激活码。激活码印在刮刮卡上,并通过线下渠道销售。其中一些卡可以使用 1 个月。其他的是3个月和1年。激活码是唯一的 10 位随机数。

当访问到期时,用户可以购买另一张激活卡并通过输入新的激活码来延长订阅。此外,如果他们要求,我们也应该能够延长他们的订阅。例如,直到某个日期(例如再延长 1 周)。

考虑到以上信息,您将如何设计用户-激活码关系的数据库?你觉得这个设计好不好?

tbl_user
----------------
id
name
status_id

tbl_user_status
----------------
id
description

tbl_activation_code
----------------
activation_code
activation_code_type_id
activation_code_status_id
user_id
activated_date
expiry_date

tbl_activation_code_type
----------------
id
description

tbl_activation_code_status
----------------
id
description

更新:仅需要激活码:

1) 初次注册时

2) 接近访问到期日期(例如 7 天)时,系统会显示通知,其中包含指向输入激活码的页面的链接

3) 过期后,当用户尝试登录时,会要求她提供激活码

因此,不希望用户在需要时键入激活码。

【问题讨论】:

  • +1 表示“随机数”。仍然有很多傻瓜在这里使用序列:(
  • 确保随机数空间足够大,否则我可能会猜到它们,这意味着您需要的地址空间是您需要的地址空间的 100-1000 倍(因此多出 3-4 个数字)。所以对你来说,听起来你可以安全地发行几百万/几千万张卡,请记住这一点。
  • Kurt,你的意思是用 10 位数的随机码我可以“安全地发行几百万/几千万张卡”吗?
  • 随机是个好主意。但是,如果您决定使用某种类型的序列,您可以将校验和数字附加到递增数字的末尾。这具有序列带来的好处(很容易准确地知道你给出了多少,相对的分布顺序),而不会在黑客或打字错误的情况下真正放弃商店。

标签: mysql database database-design data-structures


【解决方案1】:

还不错。不过,我建议您在tbl_user 中添加两个字段:

tbl_user
----------------
id
name
status_id
activated_date
expiry_date

当然,activated_date 保存它们首次激活的日期,而expiry_date 保存它们的到期日期。每当他们购买新卡时,您还需要一个更新此expiry_date 的程序。此过程应处理日期重叠的两张卡,因此用户不会在特定时间段内重复付款。例如:

  • 卡片 1 - 9 月 1 日至 9 月 30 日
  • 卡片 2 - 9 月 16 日至 10 月 15 日

那里有十五天的重叠,所以用户的activated_date应该是Sep 1,而他们的expiry_date应该是10月30日(10月15日+15日)天)。

考虑到这一点,我会更改tbl_activation_code,因为expiry_date 变得有点误导。相反,创建一个名为access_days 的列,用于计算用户的expiry_date

另外,如果您想记住已发行的卡,即使未激活,我会将tbl_activation_code 拆分为两个表:

tbl_activation_code
----------------
activation_code
activation_code_type_id
activation_code_status_id
access_days

tbl_activation
----------------
activation_code_id
user_id
activated_date

【讨论】:

  • tbl_user,当然还有created_date等其他几个字段,其实就是你提出的activated_date。至于 tbl_user 中的 expiry_date,看起来好像我们正在使用户“过期”。可能不是一个好主意,对吧?我觉得expiry_date应该是activation_code的,是根据activation_code_type_id和activated_date计算出来的。
  • 其实,迈克讲的是智慧。 Expiry_date 不代表用户过期,你可以随意重命名。但是除了 Mike 列出的好处之外,这还为您提供了一个地方查找来确定是否应该允许用户进入。这也是编写可扩展解决方案的一种方式。否则,您将不得不搜索所有卡片以查看他是否已激活任何卡片,找到它们的最大日期等等。
  • 正如 husayt 所说,您可以将 tbl_user 中的 expiry_date 字段重命名为 activation_expiry_date。关于与卡关联的到期日期,这取决于您如何查看卡。如果它们被认为是“持续时间购买”,那么 expiry_date 不属于 tbl_activation_code。例如,如果用户在同一天购买并激活两张 30 天卡,会发生什么情况。它们会被激活 30 天还是 60 天?但是,如果他们通过在一天内激活两次来“浪费”他们的卡,那么请继续将 expire_date 留在卡上(并激怒您的用户 )。
【解决方案2】:

我会考虑一些非规范化 - 目前,要确定用户当前是否具有访问权限,您必须在 tbl_activation_code 中查看该用户的潜在多条记录,以查看该用户是否有活动记录。

因此可能值得在 tbl_activation_code 中添加一个代理 IDENTITY/autonumber 字段,并在 tbl_user 中添加一个外键 - 这将指向用户当前的激活码记录,从而简化您需要查找当前状态的场景用户的访问权限。这样,用户记录将始终直接引用他们当前的激活码,而且您仍然拥有他们之前激活码的完整历史记录。

【讨论】:

  • 谢谢。为什么我不应该在 tbl_user 中使用activation_code 字段外键的任何特殊原因?为什么要附加字段?
  • 仅仅因为使用身份字段会更短 - 因此需要更少的存储空间,并且应该更有效地查询/加入/索引
  • 所以,这个自动编号将是 tbl_user 中的 FK,而 tbl_user.id 将是 tbl_activation_code 中的 FK?
  • 我认为 Mike 建议的先前方法会更好。每次您想登录用户时,他都会不查看激活码而离开。这太棒了。您只需在用户申请新卡时更改其访问到期状态,然后您就可以忘记该卡。
  • @Nuku - 是的 @husayt - 是的,我同意你所说的,我最初确实考虑过这一点。但我不建议使用这种方法的原因是因为您可以通过链接到“当前”激活码来获得额外价值——您可以轻松访问用户当前激活码的全部详细信息。有了替代方案,您就没有这个。当然,这可能不需要。
猜你喜欢
  • 1970-01-01
  • 2013-07-09
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 2014-01-03
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
相关资源
最近更新 更多