(有点)复杂的数据库结构与简单 - 使用空字段

时间:2012-10-31 21:01:50

标签: mysql database database-design database-schema

我目前正在两种不同的数据库设计中进行选择。一个复杂分隔数据比更简单的数据更好。更复杂的设计需要更多复杂查询,而更简单会有一些 null字段

考虑以下示例:

复杂:

Complicated

简单:

Simpler

以上示例用于分隔普通用户和Facebook用户(最终他们将访问相同的数据,但登录方式不同)。在第一个例子中,数据清楚地分开。第二个示例更简单,但每行至少有一个null字段。如果{1}是普通用户,则facebookUserId将为null,而usernamepassword如果是Facebook用户则为null。

我的问题是:什么是首选?优点缺点?哪一个最容易维持?

5 个答案:

答案 0 :(得分:3)

首先,柯克说。这是对每种替代设计可能产生的后果的总结。其次,值得了解其他人对同一问题的所作所为。

您概述的案例在ER建模圈中称为“ER专业化”。 ER专业化只是子类概念的不同措辞。您提供的图表是在SQL表中实现子类的两种不同方法。第一个名称为“Class Table Inheritance”。第二个名称为“Single Table Inheritance”。

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

您可以在SO中查找“ER specialization”,“single-table-inheritance”,“class-table-inheritance”和“shared-primary-key”作为标记。或者您可以在网上搜索相同的主题。您将学习的第一件事是Kirk总结得如此之好。除此之外,您将学习如何使用每种技术。

答案 1 :(得分:2)

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

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

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

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

希望这些想法能帮到你!

答案 2 :(得分:2)

好问题。

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

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

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

第二种选择与第一种选择相反。更容易,但是如何处理未来的身份验证方法以及如果需要添加一些特定于身份验证方法的信息呢?

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

答案 3 :(得分:1)

警告铃声响起,两个非常相似的桌子facebookusers和normalusers的存在。如果你得到第三种类型怎么办?还是第10个?这太疯狂了,

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

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

答案 4 :(得分:1)

让我敢于提出第三个问题。您可以引入1(或2)个表,以满足可扩展性。我个人试图避免使用非统一适用的列引入(读取:污染)实体模型的设计。让第三个表(在EAV model的方式之后)与您的users表包含多对一关系,以满足多个/变量用户相关字段。

我不确定您当前/短期需求是什么,但重新设计您的应用以满足可能,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将是列出您当前支持的各种登录类型的属性表的外键。这为您和您的用户提供了灵活性,使您的用户可以使用不同的外部服务进行多次登录,而无需更改现有系统的大部分内容