我遇到的情况涉及公司、项目和撰写项目报告的员工。
一家公司拥有许多项目、许多报告和许多员工。
一份报告由一名员工为公司的一个项目撰写。
各公司希望报告中包含不同的内容。假设一家公司想了解项目绩效和速度,而另一家公司想了解成本效益。有 5-15 个标准,每个公司都有不同的设置,所有这些标准都适用于该公司的所有项目报告。
我正在考虑不同的方法来做到这一点,但我目前的僵局是:
- 在公司表中,添加文本字段
criteria
,其中包含按顺序排列的所需条件的数组。 - 在报告表中,有一个
company_id
和列criterion1
、criterion2
等。
我完全意识到这通常被认为是可怕的数据库设计 - 不优雅且不灵活。所以,我需要你的帮助!我怎样才能更好地构建它?
结论
出于以下原因,我决定在我的案例中使用序列化选项:
- 我对标准的要求很简单 - 每位员工提交报告后,无需搜索或排序。
- 我想最大限度地减少数据库负载 - 在要实现这些负载的地方,已经有一个大页面产生开销。
- 我希望避免使数据库结构复杂化,以满足我认为相对简单的需求。
- CouchDB 和 Mongo 目前不在我的保留范围内,因此我会将它们留到更需要的时候使用。
最佳答案
这将是使用 NoSQL 的绝佳机会!对我来说这似乎是教科书的用例。因此,请前往 CouchDB或Mongo并开始黑客攻击。
使用传统的数据库,您会稍微陷入数据标准化程度的问题:
一种“好”方式(意味着非常标准化)看起来像这样:
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 中的三重或四重联接,并且您有许多几乎不执行任何操作的模型。
另一种方法是非规范化:
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
与此相关的是至少序列化标准(如果它们都是 bool 值,则可能是值)的相当聪明的方法是使用位字段。这基本上为您提供了或多或少的轻松迁移(难以删除和修改,但易于添加)和搜索能力,而无需任何开销。
实现此功能的一个很好的插件是 Flag Shih Tzu我已经在几个项目中使用过并且可以推荐。
变量列(例如
crit1
、crit2
等)。我强烈建议不要这么做。您不会获得太多好处(它仍然不太容易搜索,因为您不知道您的信息在哪一列)并且会导致可维护性噩梦。想象一下,您的数据库有几百万条记录,突然有人需要 16 个条件。原本完全没有问题的事情突然间发生了一次迁移,向数百万条记录添加了一个完全无用的字段。
另一个问题是,许多 ActiveRecord 魔法对此不起作用 - 您必须自己弄清楚
crit1
的含义 - 现在如果您不想添加验证这些字段会增加很多无意义的工作。
总结一下:看看 Mongo 或 CouchDB,如果这看起来不切实际,请继续保存您的东西 serialized 。如果您需要进行复杂的验证并且不太关心数据库负载,那么请进行标准化并采用选项 1。
关于ruby-on-rails - 可变列名的数据库设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5289099/