我正在尝试设计一个应用程序来保存学术参考信息.问题是每种不同类型的参考(例如期刊文章,书籍,报纸文章等)都需要不同的信息.例如,期刊参考既需要期刊标题,也需要文章标题,还需要页码,而书籍需要出版商和期刊文章不需要的出版日期.
因此,我是否应该将所有引用存储在我的数据库中的一个表中,并且当它们不适用时将字段留空,或者我应该有各种表,例如BookReferences,JournalReferences,NewspaperReferences,并在每个表中放入适当的引用.那么问题是它会使搜索所有参考文件变得更加困难,并且编辑也可能需要更加单独地进行.
(顺便说一句,我打算在这个项目中使用Ruby on Rails,但我怀疑这对这个设计问题有什么不同)
更新:
还有更多观点吗?我希望得到一个简单的答案,说一个特定的方法肯定被认为是"最好的" - 但通常事情并不像这样简单.单表继承选项看起来很有趣,但是我没有太多关于它的信息我可以很容易地找到 - 我可以在这个网站上发布另一个问题.
我在奥尔瓦克的回答和科里的答案之间分开了.科里的回答给出了奥尔瓦克不是最好的理由,但奥尔瓦克的答案给出了科里为什么不是最好的理由!我从没意识到这可能会如此困难......
进一步的建议非常感谢!
我会为所有引用设置一个表,但是对于元数据而言,其他表(如BookReferences等)不适用于所有引用类型.
搜索和查询并不会比较困难 - 毕竟你可以创建一个聚合所有信息的视图,就像在单表解决方案中一样,然后进一步查询该视图.
将所有内容放在一个包含大量空值的表中似乎是更简单的解决方案,但实际上它会导致很多麻烦.例如:使用单独的表,您可以定义每个BookReference 所需的字段,但如果所有字段都在一个表中,则每个字段都必须是可空的,因此是可选的.插入无效数据也会更容易,例如书籍参考也错误地包含非空的期刊名称.
编辑:有些人似乎害怕加入.不要害怕加入!如果在几个确实很繁琐的查询中使用完全相同的连接,但在这种情况下,应该在视图中定义连接,并且查询应该查询该视图.视图实际上是关系数据库中的基本抽象,您应该使用它们的原因与在代码中使用函数的原因相同:避免重复,以及封装和创建抽象.
编辑:有一些关于性能的评论.事先很难猜测数据库模式的性能,因为它通常是非直观的.例如,几个表之间的连接可以比单个表的完整表扫描更快 - 这完全取决于查询的类型,数据的性质,可用的索引等.此外,在许多数据库系统中,您可以使用物化视图等功能来优化不同查询的性能,而不会影响逻辑模型.除非你是Google或Flickr,否则"非常规化的表现"主要是货币崇拜.
"一张大桌子让生活变得更轻松":我已经看到了这种自然的结果,是一张100多列的桌子,我可以告诉你,我发现这并不是一件好事.
主要问题是这些表的设计者倾向于省略确保数据完整性所需的约束.例如,OP说:
期刊参考既需要期刊名称和文章标题,也需要页码,而书籍需要出版商和期刊文章不需要的出版日期
......这意味着以下限制:
CONSTRAINT a_journal_must_have_a_journal_title CHECK ( type <> 'journal' OR journal_title IS NOT NULL ); CONSTRAINT a_journal_must_have_an_article_title CHECK ( type <> 'journal' OR article_title IS NOT NULL ); CONSTRAINT a_journal_must_have_a_page_number CHECK ( type <> 'journal' OR page_number IS NOT NULL ); CONSTRAINT a_journal_cannot_have_a_publisher CHECK ( type <> 'journal' OR publisher IS NULL ); CONSTRAINT a_journal_cannot_have_a_publication_date CHECK ( type <> 'journal' OR publication_date IS NULL ); CONSTRAINT a_book_cannot_have_a_journal_title CHECK ( type <> 'book' OR journal_title IS NULL ); CONSTRAINT a_book_cannot_have_a_article_title CHECK ( type <> 'book' OR article_title IS NULL ); CONSTRAINT a_book_cannot_have_a_page_number CHECK ( type <> 'book' OR page_number IS NULL ); CONSTRAINT a_book_must_have_a_publisher CHECK ( type <> 'book' OR publisher IS NOT NULL ); CONSTRAINT a_jbook_must_have_a_publication_date CHECK ( type <> 'book' OR publication_date IS NOT NULL );
......我怀疑这只是冰山一角!
我希望在写完几百个这样的约束之后,设计师可能会对所有那些可以为空的列进行二次思考:)
我的建议是从正确设计数据库开始,即使用规范化来确保表只包含关于一件事(书籍,期刊等)的数据,并且这些属性存储在右表中.
如果将来它会产生性能问题,您可以将其去规范化为更少的表,但除非您拥有庞大的数据库,否则这不太可能成为问题.
创建一个表,其中包含所有引用的公共属性.
创建单独的表以保存特定于每种引用类型的属性.
另一个问题是,您是否会对单个作品进行多次引用,例如对特定期刊的数百个引用.然后规范化将建议您拥有一个包含日志(标题,作者,期刊)的表,一个包含特定于期刊(文章,页面)的参考信息的表,以及另一个包含所有参考文献共有的数据的表(参考日期,参考类型).