具有1对多关系的数据库设计效率限制为1到3

时间:2010-06-15 16:24:43

标签: sql database-design data-modeling normalization

这是在mysql中,但它是一个数据库设计问题。如果你有一对多的关系,比如银行客户到银行账户,通常你会有记录银行账户信息的表有一个跟踪账户和客户之间关系的外键。现在这遵循第三种常规形式,并且是一种被广泛接受的方式。

现在假设您要将用户限制为只有3个帐户。当前的数据库实现将支持这一点,没有什么需要改变。但另一种方法是在帐户表中有3列,其中包含3个相应帐户的ID。顺便说一句,这违反了数据库设计的第一种正常形式。

问题是以这种方式记录用户帐户关系的优点和缺点是什么?

更新

不幸的是,我不负责数据库设计。当我在数据库中看到类似的关系时,我问我的老板,数据库设计师,为什么他选择这样做。我没有真正得到一个明确的答案,或者我理解的答案有合理的理由支持它。 “当你使用数据库分配时,这是一种非常常见的关系,这就是你如何做到的。”我要求更多澄清。 ......没有把我带到任何地方,让他成为防守者。

非常感谢你们这些帖子,我真的找不到任何甚至谈到这样做的书。我发现有很多书告诉我以正确的方式做到这一点,但没有多少人给出一个破碎的例子,然后解释为什么它会吮吸。

8 个答案:

答案 0 :(得分:5)

首先,对于少于三个帐户的客户,您将有大量空白字段用于记录。

添加第四个或更多帐户将需要向表中添加列,这将再次为每个记录生成更多空白字段。

其次,如果将数据存储在单独的表中,则查询数据(例如帐户总数等)会更容易。

我们为1到N关系使用单独表格的原因是它可以帮助您避免这些问题。

答案 1 :(得分:5)

最大的问题是您的查询变得更加复杂。假设您想要与所有者查找余额超过10,000美元的所有帐户。在规范化的数据库中,这将是:

select firstname, lastname, accountnumber, balance
from account
join customeraccount using (accountnumber)
join customer using (customernumber)
where balance>10000

但是有三个accountnumber字段,它变成

select firstname, latname, accountnumber, balance
from account
join customer on customer.accountnumber1=account.accountnumber
  or customer.accountnumber2=account.accountnumber
  or customer.accountnumber3=account.accountnumber
where balance>10000

现在,将Account加入Customer的每个查询都会变得更加复杂。

迟早,有人会编写一个无法检查accountnumber3的查询,或者他试图通过复制粘贴进行三次测试,并且在复制accountnumber1两次后,他忘记更改其中一个。这是一个在阅读查询时容易忽略的错误。如果你搞砸了三个比较中的一个,那么该程序将适用于只有两个帐户的所有客户,但对于拥有三个帐户的客户则失败。这是一种很容易通过测试的问题。

当同一个客户拥有多个帐户时,您现在必须仔细考虑联接的工作方式。如果客户在某个查询中有两个符合条件的帐户,您是否希望他出现一次或两次?

您可能需要在客户的帐号字段中编制索引。现在你需要三个索引而不是一个。数据库的开销更多。

您确定最大值永远不会改变吗?因为如果它确实如此,现在必须更改检查三个插槽的每个查询以检查四个插槽。这可能是一大堆工作。

你为了这一切痛苦而获得了什么?自动执行max-3限制。少一张桌子。您可能会在某些查询上获得更好的性能,因为要连接的表少一个。然后,您可能无法获得更好的性能,具体取决于数据库引擎内部工作的许多细节和实际数据。

总而言之,我会说这几乎肯定不值得做。坚持规范化的数据库。

我从经验中说话。我做过一次非常类似的事情。我们有一个数据库,我们必须为我们组织出版的每本书记录三种类型的“经理”(#1负责预算和管理,#2负责分发,#3负责内容(即编辑)由于三者不同,我创建了三个不同的点。巨大的错误。我会更好地创建一个带有类型代码的书籍管理器表,并且只使用触发器或代码强制执行每种类型中的一个。查询将有更简单。(经验使您能够做出正确的决定。通过做出错误的决定可以获得经验。)

答案 2 :(得分:3)

<强>优点:

  • 比正常形式更快(多少?)
  • 更简单的基本操作查询(无连接)
  • 稍微轻松施加最大限制

<强>缺点:

  • 扩展
  • 添加了业务逻辑(如果客户关闭了他们的第一个帐户怎么办?转移其他帐户?)
  • 浪费的空间(如果普通用户没有3个账户,则相当可观)
  • 汇总更难以获得的指标(即:确切的帐户总数)
  • 您无法声明您的数据库已标准化

根据要求,这两个选项都是有效的。如果可能,对差异进行基准测试并查看性能,计算存储差异以确定是否值得部署。

然而,我可能会选择使用触发器强加帐户限制,因为这样可以提供最简单的可维护性,而不是浪费磁盘空间,未来的开发人员也不会想知道为什么我甚至无法获得1NF。

答案 3 :(得分:1)

优势:更高的性能,无需加入关系表

缺点:违反第一范式(但可能违反更严重的表现)

取决于你;)

答案 4 :(得分:1)

  

现在假设您要限制用户只有3个帐户。

这涉及一个可能会发生变化的幻数。

不要相信任何说有“限制”的人。今天的绝对最大值是明天的最低值。

不参与在数据库中强制执行此愚蠢行为。所有“限制”只不过是“当前应用的典型值”,并且会发生变化。

使用普通外键的普通1对多,忽略幻数“3”。

答案 5 :(得分:1)

如果有业务规则更改,则3列方法会受到影响(IE:用户现在可以拥有4个帐户,啊啊啊......)。这将需要ALTER表语句与INSERT,并且必须重新访问所有支持逻辑以适应新列 - 从开发角度来看, 非常 代价昂贵。此外,当3NF不受影响时,数据库确实有column limit

答案 6 :(得分:0)

在多列上拆分帐号的可能缺点:

您必须重复查询逻辑和任何其他引用帐号的代码。

如果少于三个,则必须使用一些占位符而不是帐号。

它不会自动违反First Normal Form,因为1NF只不过是关系本身的定义。这不是一个非常实用的设计(DRY原则)。

答案 7 :(得分:0)

听起来像是在一杯水中淹死了!为什么不在每个细节账户表中添加一个计数器列,如果你试图添加一个新的账户行,请检查一下柜台?