2012-10-31 50 views
3

我目前选择两种不同的数据库设计。一个复杂其中分离数据更好,那么更简单的一个。更复杂的设计将需要更多复杂查询,而更简单一个将有几个null字段(有点)复杂的数据库结构与简单 - 空字段

考虑下面的例子:

复杂:

Complicated

简单:

Simpler

上述例子用于分离定期用户和Facebook用户(他们最终将访问相同的数据,但以不同的方式登录)。在第一个例子中,数据是分开的。第二个例子是简单的方法,但每行至少有一个null字段。如果它是普通用户,则facebookUserId将为空,而如果它是Facebook用户,则usernamepassword将为空。我的问题是:什么是首选?优点缺点?随着时间的推移,哪一个最容易维护?

+0

我更关心为什么要将会话密钥存储在用户表中。 – RedFilter

+0

@RedFilter为什么不呢?它是在登录时生成的,以验证用户身份,无论是Facebook用户还是普通用户。对不起,如果我错过了这一点,餐桌设计不是我的专长;-)。 – Zar

+1

如果用户想要从两个不同的设备/浏览器同时登录,该怎么办? – RedFilter

回答

2

伟大的问题。

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

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

折衷的是,它需要更多的努力来查询,它将需要更多的努力来选择和插入,它可能会变得更加混乱。你不需要十几个不同的认证方法。除非你从中获得一些好处,否则你并不是真的需要两个认证方法的表。你是否需要这种灵活性?身份验证方法都是类似的 - 他们将有一个用户名和密码。这种抽象可以让你存储更多特定于方法的信息,但是这些信息是否存在?

第二个选项正好相反。更容易,但您将如何处理未来的身份验证方法,以及如果您需要添加一些身份验证方法的特定信息?

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

+0

很好的答案,你提出了很多好的观点。非常感谢您的回答 - 真心赞赏! – Zar

2

这取决于您使用的数据库。例如Postgres有表继承会为你的例子是巨大的,看看这里: http://www.postgresql.org/docs/9.1/static/tutorial-inheritance.html

现在,如果你没有表继承,你仍然可以创建视图,简化您的查询,因此,“复杂”的例子这是一个可行的选择。 现在,如果你有无限的时间比第一个(为这个简单的例子,并喜欢表继承)。

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

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

希望这些想法能帮助你!

+1

该链接(为什么不应该使用空值)是奇怪的,极端错误的,imo。 –

+0

我删除了链接(因为我明白你的意思)。下次我会更仔细地阅读我的参考资料。 – Tim

+0

这是一个有趣的阅读,但! –

1

警告铃声响亮地响起,两个非常相似的表facebookusers和normalusers的存在。如果你得到第三种类型呢?还是第十?这是疯了,

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

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

+0

我明白你对用户类型标志的想法,但如果不在单独的表中,这个用户类型唯一数据将被存储在哪里?非常感谢您的回复! – Zar

3

首先,柯克说了什么。这是每种替代设计可能带来的后果的一个很好的总结。其次,值得了解其他人对同一问题所做的工作。

你所概述的情况在ER建模界被称为“ER专业化”。 ER专业化只是针对子类概念的不同措辞。您提供的图表是在SQL表中实现子类的两种不同方式。第一个名称是“Class Table Inheritance”。第二个名称是“Single Table Inheritance”。

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

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

+0

非常感谢您的回复,很好的解释。 – Zar

+0

我认为柯克的答案会被标记为“正确”。我的回答虽然很有价值,但仅仅为Kirk所说的增加了一些细节。 –

+0

我想这很公平,我不能选择。两个很好的答案! – Zar

1

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

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

+0

好想法,我来看看吧。非常感谢! – Zar