更好的数据库设计是使用更多的表还是更多的列?

99

一位前同事坚称拥有更多表格且每个表格的列数更少的数据库比拥有更少表格且每个表格的列数更多的数据库更好。例如,您将拥有一个名字表、一个地址表、一个城市表等,而不是一个客户表格,其中包含名称、地址、城市、州、邮政编码等列。

他认为这种设计更高效和灵活。也许它更灵活,但我无法评论其效率。即使它更有效率,我认为增加的复杂性可能会抵消这些收益。

那么,相对于少量表格但每个表格包含更多列,是否有更多表格但每个表格包含更少列的重要优势呢?

18个回答

74

我在设计数据库时遵循几个相当简单的经验法则,我认为这些法则可以用于帮助做出像这样的决策...

  1. 偏向范式化。非范式化是一种优化形式,具有所有必要的权衡,因此应该采取你不需要它的态度。
  2. 确保引用数据库的客户端代码与架构分离,这样重新设计不需要对客户端进行重大改进。
  3. 当它提供明显的性能或查询复杂性优势时,不要害怕非范式化。
  4. 当数据量和使用场景允许时,使用视图或下游表来实现非范式化,而不是非范式化模式的核心架构。

这些规则的通常结果是,初始设计将偏向于表而不是列,并专注于消除冗余。随着项目的进展和非范式化点的确定,整体结构将朝着在有限的冗余和列扩展换取其他有价值的收益之间妥协的平衡发展。


“下游表”究竟是什么? - olive
1
我所说的“downstream”是指“数据流”的上下文。这基本上意味着您有一个使用规范化表作为源的过程,并以某种方式转换数据,然后将结果存放在其他地方的过程。 - Chris Ammerman

13

这似乎不是关于表/列的问题,而是有关规范化的问题。在某些情况下,具有高度规范化(在此情况下为“更多表”)是好的和干净的,但通常需要大量JOIN才能获得相关结果。而且对于足够大的数据集,这可能会降低性能。

Jeff 在 StackOverflow 设计方面写了一些内容,可以参考他引用的Dare Obasanjo的文章。


2
根据我的经验,这是显然错误的。我曾经处理过连接数十个表格的查询,每个表格都包含100万行以上的数据,只要你按照主键进行连接,结果会非常快速返回。 - JosephStyons
2
什么是“快速”?如果您正在运行一个试图服务于每秒数千个页面视图的网站,“足够快”的意义与单个用户数据库完全不同,因为您所关心的只是用户的响应时间。 - Chris Upchurch
只要您在主键上进行连接,结果就会非常快速。但是根据我的经验,当涉及到更多表时,连接通常会在非主键、非索引列等上发生。 - swilliams
1
通常情况下,规范化和随后的表连接可以提高性能,因为根据定义,您可以更加有选择性并避免表扫描 - 这是最慢的选择方法。 - Ed Guiness
1
糟糕的设计通常是性能不佳的最大因素,而不是规范化。 - Ed Guiness
我有一个实时数据处理应用程序,但连接操作使查询变得很慢。我对数据进行了反规范化处理,一切都好了,当请求数量减少时,它会被集成回规范化的数据库中。 - Quibblesome

13

我认为增加更多的表是可以的,但只能到一定程度。以你的例子为例,如果你将用户信息分成两个表,比如用户表和地址表,这样就可以让一个用户拥有多个地址了。其中一个显而易见的应用场景就是有一个用户需要拥有不同的账单和邮寄地址。

支持使用单独的城市表的观点是,你只需存储每个城市的名称一次,然后在需要时引用它即可。虽然这样可以减少重复,但在这个例子中,我认为这种方法过于复杂了。虽然可以更节省空间,但当你从数据库中选择数据时会付出连接查询(join)的代价。


6
每个表只应包括与由主键唯一标识的实体相关的列。如果数据库中的所有列都是同一实体的属性,则只需要一个包含所有列的表。
但是,如果任何列可能为空,则需要将每个可空列放入其自己的表中,并使用外键将其连接到主表以进行规范化。这是一个常见的情况,因此为了更清晰的设计,您可能需要向现有表添加更多的表而不是列。另外,通过将这些可选属性添加到它们自己的表中,它们将不再需要允许空值,从而避免了一系列与NULL相关的问题。

5

这取决于你的数据库类型。例如,MS SQL Server 倾向于使用较窄的表格,这也是更规范化的方法。其他数据库引擎可能会倾向于相反的方式。大型机往往属于这一类别。


你好 Joel,更窄的表是否意味着表的数量变少?以上面的例子为例,如果公司地址只需填写一个,则把所有地址字段放在单独的表中还是放在同一张表中更好?另外,如果公司做了很多采购,我想存储摘要(例如“TotalOrders,TotalOrderValue,TotalComplains”等),即使它与公司表是1对1的,把这些字段放在不同的表中是否更好? - Sam
1
@Sam,“更窄”意味着每个表格的列数更少,因此可能需要更多的表格来处理相同的字段。存储摘要通常不是一个好主意。如果正确建立索引,即使对于大公司,在请求时构建摘要仍然可以高效完成。 - Joel Coehoorn

5
一个完全规范化的设计(即“更多表格”)更加灵活、易于维护,避免了数据重复,这意味着你的数据完整性将更容易得到执行。这些都是规范化的强有力的理由。我会选择先进行规范化,然后只在看到性能成为问题时才去非规范化特定的表格。我的经验是,在现实世界中,即使是非常大的数据集,你也不需要达到需要非规范化的程度。

同意。我只是为了减少查询复杂度而去反规范化,通常是为了消除ORM中的某些阻抗不匹配。从未因为需要性能优化而进行反规范化,即使在大规模情况下也是如此。 - Ben Simmons

4

像其他事情一样:这取决于情况。

关于列数与表数之间的硬性规定并不存在。

如果您的客户需要拥有多个地址,则单独创建一个表是有意义的。如果您有很好的理由将City列规范化为自己的表,那么也可以这样做,但我以前从未见过,因为它是自由格式字段(通常情况下)。

表数量多、规范化的设计在空间上非常高效,看起来“教科书式”,但可能变得非常复杂。它看起来很好,直到你不得不进行12次连接才能获得客户的姓名和地址。这些设计在最重要的查询性能方面并不自动表现出色。

如果可能的话,请尽量避免复杂性。例如,如果一个客户只能拥有两个地址(而不是任意多个),那么将它们全部保存在一个表中可能是有意义的(CustomerID、Name、ShipToAddress、BillingAddress、ShipToCity、BillingCity等)。

这里是Jeff的帖子


3

如果这些一对一关系中的任何一个在将来可能变成一对多或多对多,那么多表数据库会更加灵活。例如,如果您需要为某些客户存储多个地址,则拥有客户表和地址表会更容易。我真的看不出你可能需要复制地址的某些部分但不是其他部分的情况,因此单独的地址、城市、州和邮政编码表可能有点过头了。


我有关于用户信息的40个唯一字段,它们是从用户认证系统中的一对一关系。您认为如果我将这些40列保留在一个表中是否可以?如果我将它们分开,那么我的查询需要编写更多的连接 :-(。您能否提供建议? - vkrams

2

减少表格列数有其优点,但您还需要查看上述场景并回答以下问题:

客户是否被允许拥有多个地址?如果不是,那么地址的单独表格就不是必需的。如果是,那么单独的表格变得很有用,因为您可以根据需要随时轻松添加更多的地址,而向表格添加更多的列则变得更加困难。


1
当你设计数据库时,应尽可能接近数据的含义而不是你的应用需求!
一个好的数据库设计应该可以持续20年而不需要更改。
客户可能有多个地址,这是现实。如果您决定在第一次发布中将应用程序限制为一个地址,则涉及到您的应用程序设计而不是数据!
最好使用多个表而不是多个列,并使用视图来简化查询。
大多数情况下,数据库性能问题与网络性能有关(链式查询只有一行结果,提取不需要的列等),而不是查询的复杂性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接