【问题标题】:Storing duplicate fields: good or bad [closed]存储重复字段:好或坏[关闭]
【发布时间】:2017-01-31 23:37:16
【问题描述】:

假设一个用户有这样的帖子表:

id=1 的帖子是用户发布的第一个帖子。 id=2 的帖子——是对帖子所做的编辑,id=3——帖子的最新当前版本。

post_param_auser_id 无法在整个版本中更改 - 自第一个版本以来它们始终保持不变。所以我们可以这样存储它:

所以问题是:以第二种方式存储它会不会更好,没有重复?这样,要获得用户帖子的当前版本,我们必须加入第一个版本并一直检查它的user_id或者在这种情况下可以存储重复字段吗?

附言这是有问题的,因为我们希望避免在整个版本中无法更改的值的重复和意外更改,因此我们希望将它们全部存储在一个地方

【问题讨论】:

  • 只有傻瓜才会这样做#2
  • #1 无论如何都是非规范化的。
  • @Drew 那么最好的方法是什么?拆分到不同的表?
  • 这是个人喜好问题。我为数据标准化而努力。上面的表格看起来像某些层次结构下的评论数据,在我的书中不应该包含非规范化数据。您需要在层次结构中显示其上方的一两个表,因为这里没有明确的含义。

标签: mysql postgresql database-design


【解决方案1】:

取实体Post,看看简单的元组:

ID  User_ID  Post_Param_A  Comment
 1       69           foo  This is a post

这是完全标准化的。但是,帖子可能会进行编辑,您希望跟踪所做的更改。因此,您添加另一个字段来跟踪更改。但是,添加日期时间字段而不是增量值会更有意义。

ID  EffDate       User_ID  Post_Param_A  Comment
 1  1/1/16 12:00       69           foo  This is a post

这有两个好处:1)如果您跟踪更改,无论如何您都想知道这个版本是什么时候保存的;2)您不必找到帖子的最大增量值来找出要更改的值保存每个新版本。只需保存当前日期和时间。

但是,无论是增量值还是日期,都会出现问题。在简单行中,每个字段对 PK 都有函数依赖。在版本行中,User_ID 和 Post_Param_A 保持对 PK 的依赖,但 Comment 现在依赖于 PK EffDate。

元组不再在 2nf 中。

所以解决方案是一个简单的规范化问题:

ID  User_ID  Post_Param_A
 1       69           foo

ID  EffDate        Comment
 1  1/1/16 12:00  This is a post
 1  1/1/17 12:00  An edit was made
 1  1/1/17 15:00  The last and current version (so far)

在新表中使用 (ID, EffDate) 复合 PK。

阅读最新帖子的查询有点复杂:

select  p.ID, v.EffDate, p.User_ID, p.Post_Param_A, v.Comment
  from  Posts p
  join  PostVersions v
    on  v.ID = p.ID
   and  v.EffDate = (
        select  Max( v1.EffDate )
          from  PostVersions v1
         where  v1.ID = p.ID
           and  v1.EffDate <= today )
   and  p.ID = 1;

这并不像看起来那么复杂,而且速度惊人。真正简洁的功能是——如果您将“今天”替换为 1/1/17 13:00,则结果将是第二个版本。因此,您可以使用相同的查询来查询现在或过去。

另一个简洁的功能是通过从“today”查询创建一个视图来实现的,并删除了最后一行(“and p.ID = 1”)。此视图将显示所有帖子的最新版本。在视图上创建触发器,这允许只对当前版本感兴趣的应用程序在不考虑底层结构的情况下完成工作。

【讨论】:

    【解决方案2】:

    您可以有一个单独的表来存储每个post_idpost_param_a,这样您就不需要有 NULL 值或重复值。

    【讨论】:

      【解决方案3】:

      第一种解决方案更好,因为user_idpost_id 对齐并避免各种解释。

      这样,要获得用户帖子的当前版本,我们必须加入第一个版本并始终检查其 user_id。

      您是否考虑添加一个字段timestamp,以便您始终可以获取帖子的最新版本?

      在第二种解决方案中,当数据增长时,NULL 可能是不明确的。甚至查询也会很困难,每个 SQL 都应该精心设计,以考虑 NULL 情况及其具体含义。

      第三种解决方案可能是使用 2 个分开的表格对表格进行规范化,例如postpost_history。正如您在问题中提到的那样,post_param_auser_id 不能在整个版本中更改——它们自第一个版本以来始终保持不变。在这种情况下,

      • 在表post中,您可以存储与帖子相关的信息,这些信息是永久性的(不会更改):idparam_auser_idcreated_at ...
      • 在表post_history中,您可以存储与每个版本/修改相关的帖子相关信息:version_idcommentmodified_at ...您可以为第二个添加FK约束表示post_history.post_id = post.id 的表

      【讨论】:

        猜你喜欢
        • 2012-10-30
        • 1970-01-01
        • 1970-01-01
        • 2011-05-04
        • 2012-05-02
        • 1970-01-01
        • 1970-01-01
        • 2012-09-27
        • 2010-11-05
        相关资源
        最近更新 更多