【问题标题】:A database design for variable column names可变列名的数据库设计
【发布时间】:2011-03-13 11:35:14
【问题描述】:

我遇到的情况涉及撰写项目报告的公司、项目和员工。

一家公司拥有许多项目、许多报告和许多员工。
一份报告由一名员工为公司的一个项目撰写。

每个公司都希望在报告中包含不同的内容。假设一家公司想了解项目绩效和速度,而另一家公司想了解成本效益。有 5 到 15 条标准,每个公司设置的不同,都适用于该公司的所有项目报告。

我正在考虑不同的方法来做到这一点,但我目前的僵局是这样的:

  • 在公司表中,添加文本字段criteria,其中包含按顺序所需的条件数组。
  • 在报告表中,有一个company_id 和列criterion1criterion2 等。

我完全清楚,这通常被认为是糟糕的数据库设计 - 不优雅且不灵活。所以,我需要你的帮助!我怎样才能更好地构建它?


结论

出于以下原因,我决定使用序列化选项:

  1. 我对标准的要求很简单 - 一旦报告由每个员工提交,就不需要搜索或排序。
  2. 我想最大程度地减少数据库负载 - 在将要实现这些功能的地方,已经有一个带有开销的大页面。
  3. 我想避免使我的数据库结构复杂化,因为我认为这是一个相对简单的需求。
  4. CouchDB 和 Mongo 目前不在我的库中,因此我会将它们保存起来以备不时之需。

【问题讨论】:

  • 您能写几句为什么需要报表表吗?在我看来,它完美地复制了公司表中的信息。我错过了什么?
  • 公司表有company_name之类的东西。报告是员工对公司某个项目的报告,根据多项标准对该项目进行评级。

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

这将是使用 NoSQL 的绝佳机会!对我来说似乎是教科书用例。所以前往CouchDBMongo 并开始黑客攻击。

使用传统数据库时,您会略微陷入数据标准化程度的问题:

  1. 一种“好”的方式(意思是非常规范化)看起来像这样:

    class Company < AR::Base
      has_many :reports
      has_many :criteria
    end
    
    class Report < AR::Base
      belongs_to :company
      has_many :criteria_values
      has_many :criteria, :through => :criteria_values
    
    end
    
    class Criteria < AR::Base # should be Criterion but whatever
      belongs_to :company
      has_many :criteria_values
      # one attribute 'name' (or 'type' and you can mess with STI)
    end
    
    class CriteriaValues < AR::Base
      belongs_to :report
      belongs_to :criteria
      # one attribute 'value'
    end
    

    这使得 NoSQL 中的一些事情变得非常简单和快速,在 SQL 中使用三重或四重连接,并且您有许多模型几乎什么都不做。

  2. 另一种方法是去规范化:

    class Company < AR::Base
      has_many :reports
      serialize :criteria
    end
    
    class Report < AR::Base
      belongs_to :company
      serialize :criteria_values
    
      def criteria
        self.company.criteria
      end
      # custom code here to validate that criteria_values correspond to criteria etc.
    end
    

    与此相关的是至少序列化标准(如果它们都是布尔值,可能还有值)的相当聪明的方法是使用位字段。这基本上为您提供了或多或少的简单迁移(难以删除和修改,但易于添加)和搜索能力,而无需任何开销。

    一个很好的插件是Flag Shih Tzu,我在几个项目中使用过,可以推荐。

  3. 可变列(例如crit1crit2 等)。

    我强烈建议不要这样做。你没有得到太多好处(它仍然不是很容易搜索,因为你不知道你的信息在哪一列)并且它会导致可维护性的噩梦。想象一下,你的数据库有几百万条记录,突然有人需要 16 个标准。本来完全没有问题的事情突然发生了一次迁移,为数百万条记录添加了一个完全无用的字段。

    另一个问题是,很多 ActiveRecord 魔法都不能用这个 - 你必须自己弄清楚 crit1 的意思 - 现在如果你不想在这些字段上添加验证,那么添加很多无意义的工作。

总结一下:看看 Mongo 或 CouchDB,如果这看起来不切实际,请继续保存你的东西 serialized。如果您需要进行复杂的验证并且不太关心数据库负载,那么请规范化并采用选项 1。

【讨论】:

  • 嗨 Jakub - 这个系统已经在 MySQL 上开发了几个月 - 这是一个相对较小的部分!
  • 你可以随时混搭。也是出于这个原因,我包括了第二段。
  • 你能解释一下CriteriaValue这句话吗?这听起来像是我正在寻找的那种信息。
  • 只是一个想法 - 是序列化更快,还是让数据库拉 5-15 个额外的记录?
  • Jakub - 我会继续思考这个问题。我同意你的观点,可变列不是一个好主意。我会尽快回复您,非常感谢。与此同时,你的任何其他想法也会很棒:)
【解决方案2】:

好吧,当您说“到公司表,添加文本字段标准,其中包含按顺序所需的标准数组”时,这听起来像是公司表想要标准化:您可能会在 15 个中的一个中分解每个标准名为“criterion1”、...、“criterion15”的列,其中任何或所有列都可以默认为空。

对我来说,您的报告表走在了正确的轨道上。该表中的每一行可能代表一个报告;并且可能有相应的列“criterion1”,...,“criterion15”,正如你所说,每个单元格都说明公司在该列的标准上做得如何。每个公司将有多个报告,因此您需要在报告表中添加一个日期(或报告编号或类似)列。那么日期加上公司id就可以成为复合键;并且公司 id 可以是非唯一索引。报告日期/编号/某些标识符也是如此。并且不要忘记报告员工 ID 的列。

报告表中的所有标准列都可以为空,这意味着(可能)员工没有报告此标准;或者此标准(列)不适用于此报告(行)。

这似乎可以正常工作。我认为您不需要加入。它看起来非常简单,至少在这些天真无知的眼睛里是这样。

【讨论】:

    【解决方案3】:

    创建一个criteria 表,列出每个公司的条件 (company 1 .. * criteria)。

    然后,创建一个 report_criteria 表 (report 1 .. * report_criteria),其中列出了基于 criteria 表 (criteria 1 .. * report_criteria) 的特定报告的条件.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-16
      • 1970-01-01
      相关资源
      最近更新 更多