我们希望在数据库中存储user
表。对于每个用户,有许多属性,例如年龄,性别,出生日期等。
我们当然可以将这些共同的属性建模为我们的user
表中的列,但是,当我们想要添加新属性时,它会变得不方便,因为我们必须修改表以添加额外的列,这个user
表可能很大。特别是,如果我们有多种类型的用户并且每种用户类型可能具有一些独特的属性,情况会更糟。
或者,我们可以采用更灵活的设计,我们使用具有以下模式的单独表格:
user_id | attribute_id | attribute_name | attribute_value
这样每个用户可以占用几行,每行包含特定属性的数据。这样,我们不必担心向用户(或用户类型)添加新属性。然而,存在另一个问题:每个属性的数据类型可能彼此不同,例如,有些可能是int,有些可能是浮点数,有些可能是字符串。作为回应,我们可以使用另一个表来将数据类型映射到属性,例如:
attribute_id | data_type
或者,我们可以简单地将所有内容存储为字符串,但不知何故,我认为就所需空间量而言,这将是一个坏主意。
所以,这里存在权衡模式的灵活性和模式的复杂性/碎片之间的权衡,我想知道哪一个总体上比另一个更有利,或者,如果有第三个更好的方式这样做。
欢迎任何评论/建议!谢谢。
答案 0 :(得分:2)
听起来您可能正在考虑动态数据库 TM 。
在我看来,这是错误的方式;主要是因为你列举的原因。
您的attribute
表必须将所有内容存储为字符串,然后如您所说将其映射回来。这不必要地使事情复杂化,这意味着无论何时从数据库中进行选择或进行比较,都必须使用attribute_data_types
表将每个值转换回原始数据类型。或者您可以选择沿着另一条路线,每个数据类型都有一列,并以某种方式动态选择要更新或选择的列,具体取决于您使用的数据类型。
如果确实沿着这条路线前进,我可以建议您将数据类型添加到该表中,使用检查约束强制执行而不是attribute_data_types
。数据类型的数量不会经常更改,您可以通过使用此类约束来停止向数据集添加无效类型。
以下是关于动态数据库可能遇到的问题的previous question。
通常,我会将数据存储在同一级别,最好是在同一个表中,作为与之关联的唯一ID。因此,如果您有一个专门加入用户的属性,我会接受命中并将列添加到users
表。您没有指定用户可能希望拥有多少属性,因此从长远来看这可能会变得荒谬,但您不需要长时间担心它。
如果你担心添加额外的列,你可以在开头做一个可怕的黑客,并添加20个额外的列new_attribute1, ..., new_attribute20
,然后在你使用它们时重命名。
你提到你正在考虑实施用户类型......无论用户,出生日期,姓名等都不会消失,你会想要存储一些数据。
虽然我不喜欢将所有内容存储在user
表中,但您可以将所有静态属性(出生日期等)保存在user
表中,然后创建一个第二个表user_attributes
,user_id
上的唯一表,用于存储不太通用的表,您只需加入不太通用的查询。它会保持用户表的大小。
在一天结束时,正如Richard A所评论的那样,没有正确的方式;你必须做适合你的事。如果可能的话,先做一些测试,看看哪种测试最适合你自己的情况。
在旁注中,永远不要像你提到的那样存储年龄。它每年都在变化,你必须不断更新你的表;只需存储出生数据,并在获取数据时进行计算。
答案 1 :(得分:1)
我同意这个问题没有一个答案。
恐怖故事时间:
我必须根据所谓的“指示性信息”来实施由大学教授开发的设计。这个概念基本上是80/20规则。在设计数据库表时,如果要使用/填充数据列80%的时间它进入基表。否则它进入“ IndiciativeInfo ”表。
“IndicativeInfo”表变成了所有类型的杂项数据的庞大的hodgepdge集合。什么样的恶梦。您无法内部连接此表,因此您必须对此表中可能已存在的每种20%数据类型执行单独的辅助查找。
设计花了将近6个月的时间在纸上冲洗。当它最终投入开发时,设计师(大学教授)放弃了该项目。
这个故事的道德......永远不要为杂项数据制作一个全能表。
如果您要使用不同的用户类型,请尝试实施超级/子类型设计。
这个概念很简单。一个基表表示用户包含所有用户共有的所有数据。这是 SuperType表。每个用户组都有自己独立的子类型表。
我将这个设计用于基于网络的房地产数据库系统。我创建了一个名为属性的 SuperType 表和几个 SubType 表(住宅,公寓,商业,MultiTenant,土地) 。 SubType表包含每个子类型共同的值。这样我就可以查询所有属性,然后深入查看子类型。
答案 2 :(得分:0)
我想提出另一点思考设计:性能。
设计架构有几种方法可以满足您的要求。问题不仅在于编程的优缺点,还在于绩效。您可以拆分表,但如果大多数屏幕或查询始终需要某个属性,将来会出现性能瓶颈。相反,如果您将属性放在一个表中,但只需要在几个屏幕或查询中,那么在一些更突出的屏幕或查询中就会出现性能瓶颈。
除了编程思想之外,我曾经考虑过数据库中存在大量数据时的性能。
例如,如果我需要查询来自属性的条件,表示为数字数据,我想将其用作数据库中的整数类型。这样的策略可以让数据库有机会在不费力的情况下构建索引,并查询索引的优势。
虽然很难预见将来会发生什么,但是刨平比什么都不做要好。