4

我目前正在两种不同的数据库设计之间进行选择。一种复杂的可以更好地分离数据,而不是更简单的一种。更复杂的设计需要更复杂的查询,而更简单的设计需要几个null字段

考虑以下示例:

复杂:

复杂

更简单:

更简单

上述示例用于区分普通用户和 Facebook 用户(他们最终将访问相同的数据,但登录方式不同)。在第一个示例中,数据明显分开。第二个例子更简单,但每行至少有一个null字段。facebookUserId如果是普通用户,则为空,而username如果password是 Facebook 用户,则为空。

我的问题是:什么是首选?优点缺点?随着时间的推移,哪一个最容易维护?

4

5 回答 5

3

首先,柯克说了什么。它很好地总结了每种替代设计的可能后果。其次,值得了解其他人在相同问题上做了什么。

您概述的案例在 ER 建模界被称为“ER 专业化”。ER 专业化只是子类概念的不同措辞。您展示的图表是在 SQL 表中实现子类的两种不同方式。第一个名为“类表继承”。第二个名称为“单表继承”。

如果您确实使用类表继承,您将需要应用另一种技术,该技术名为“共享主键”。在这种技术中,facebookusers 和 normalusers 的 id 字段将是来自用户的 id 字段的副本。这有几个优点。它加强了关系的一对一性质。它在子类表中保存了一个额外的外键。它会自动提供使连接运行得更快所需的索引。并且它允许一个简单的简单连接,将专用数据和通用数据放在一起。

您可以在 SO 中查找“ER 专业化”、“单表继承”、“类表继承”和“共享主键”作为标签。或者您可以在网上搜索相同的主题。您将学到的第一件事是柯克总结得很好。除此之外,您将学习如何使用每种技术。

于 2012-11-01T09:41:59.533 回答
2

这取决于您使用的数据库。例如,Postgres 具有对您的示例非常有用的表继承,请看这里: http ://www.postgresql.org/docs/9.1/static/tutorial-inheritance.html

现在,如果您没有表继承,您仍然可以创建视图来简化查询,因此“复杂”示例在这里是一个可行的选择。现在,如果您有无限的时间,那么我会选择第一个(对于这个简单的示例,并且首选表继承)。

但是,这会使事情变得更加复杂,因此会花费您更多的时间来实施和维护。如果您有许多这样的表层次结构,它也会对性能产生影响(因为您必须连接许多表)。我曾经开发过一个过度使用这种层次结构的数据库模式(在概念上)。我们最终决定在概念上保留层次结构,但在实现中扁平化层次结构,因为它变得如此复杂以至于不再可维护。

当您扁平化层次结构时,您可能会考虑不使用null值,因为这也可以证明使事情变得更加困难(或者您可以使用 a-1或其他东西)。

希望这些想法对你有帮助!

于 2012-10-31T22:34:01.730 回答
2

好问题。

这适用于您可能选择实现的任何抽象,无论是在代码中还是在数据库中。你会为 Facebook 用户和“普通”用户编写一个单独的类,还是在一个类中处理这两种情况?

第一个选项更复杂。为什么复杂?因为它更具扩展性。您可以轻松地包含其他身份验证方法(例如 Twitter ID 表),或扩展 Facebook 表以包含...一些其他 Facebook 特定信息。您已将特定于每种身份验证方法的信息提取到其自己的表中,从而使每种方法都独立存在。这很棒!

权衡是查询需要更多的努力,选择和插入需要更多的努力,而且可能会更混乱。您不希望有十几个表用于十几种不同的身份验证方法。除非您从中获得一些好处,否则您并不真的想要两个表用于两种身份验证方法。你需要这种灵活性吗?身份验证方法都相似——它们都有用户名和密码。这种抽象让您可以存储更多特定于方法的信息,但这些信息是否存在?

第二种选择与第一种相反。更简单,但是您将如何处理未来的身份验证方法以及如果您需要添加一些身份验证方法特定的信息怎么办?

我个人会尝试评估此身份验证组件对系统的重要性。记住 YAGNI -你不会需要它- 不要过度设计。除非您需要第一个选项提供的可扩展性,否则请选择第二个。如有必要,您可以随时提取它。

于 2012-10-31T23:46:55.837 回答
1

两个非常相似的表 facebookusers 和 normalusers 的存在,警钟响亮。如果你得到第三种类型怎么办?还是第十名?疯了吧,

应该有一个带有属性列的用户表来显示用户的类型。一个用户就是一个用户。

尽可能保持数据模型简单。不要通过数据结构构建太多功夫。将其留给应用程序,这比更改数据库要容易得多!

于 2012-10-31T23:40:17.853 回答
1

让我敢建议第三个。您可以引入 1 个(或 2 个)表来满足可扩展性。我个人尽量避免会引入(阅读:污染)具有非统一适用列的实体模型的设计。让第三个表(在EAV 模型之后)包含与您的用户表的多对一关系,以适应多/可变用户相关字段。

我不确定您当前/短期的需求是什么,但是重新设计您的应用程序以迎合 Twitter 或linkedIn 用户可能会很痛苦。如果您可以facebookUserId像这样将列的内容抽象为属性表

 user_attr{
 id PK
 user_id FK
 login_id
  }

现在,上述定义足以满足您当前的需求。如果操作正确,EAV 应该看起来更像这样:

 user_attr{
 id PK
 user_id FK
 login_id
 login_id_type FK
 login_id_status //simple boolean flag to set the validity of a given login
  }

login_id_type列出您当前支持的各种登录类型的属性表的外键在哪里。这为您和您的用户提供了灵活性,因为您的用户可以使用不同的外部服务进行多次登录,而无需更改大部分现有系统

于 2012-11-02T05:45:18.220 回答