为什么使用common-lookup表来限制实体的状态错误?

问题描述 投票:22回答:5

根据Anith Sen的Five Simple Database Design Errors You Should Avoid,使用公共查找表来存储实体的可能状态是一个常见的错误。

编辑+答案:Anith文章中的数字没有很好的标注 - 我认为图1和图2都是糟糕设计的例子,而图2是好的设计。 P,在那里担心了一会儿。

综上所述:

  • 查找表:好。
  • 通用查找表:不好。

我将在下面提出我的问题以供参考。


给出以下原因:

  1. “你失去了确保准确数据的手段;约束。通过将不同的实体组合到一个表中,你没有声明方法来约束某个类别的值。” 限制价值如何失去准确性?
  2. “您必须将每种数据类型表示为具有此类通用查找表的字符串。” 如果我想表示另一种数据类型,我可以在其查找表中添加一列。
  3. “你致力于坚强和随后的复杂性。” 怎么样?
  4. 第四,也是最后,您面临着物理实现问题。 我不明白为什么。

我不同意给出的大多数理由,并希望对我的错误进行客观批评?逻辑。

我的例子:

引用维修服务中的工作示例,其中许多可能的状态通常具有自然流程,让我们来看一个JobStatus表:

  1. 预订
  2. 分配给技师
  3. 诊断问题
  4. 等待客户确认
  5. 修理并准备好接送
  6. 修理和Couriered
  7. 无法弥补并准备好接送
  8. 引用被拒绝

可以说,这些状态中的一些可以归一化为像Couriered ItemsCompleted JobsQuotes这样的表(具有待定/接受/拒绝状态),但这感觉就像不必要的模式复杂化。

另一个常见示例是用于限制订单状态的OrderStatus表:

  1. 有待
  2. 已完成
  3. 取消
  4. 退款

状态标题和描述在一个地方进行编辑,并且易于作为带有外键的下拉列表用于动态数据应用程序。这对我来说过去很有用。如果业务规则要求创建新的订单状态,我可以将其添加到OrderStatus表,而无需重建我的代码。

为什么这是一个不好的做法?


编辑:我在我的问题中加入了Anith的理由,并试图保持客观。

--

database-design
5个回答
12
投票

Anith Sen建议反对的是所有查找代码都有一个查找表。这就是他的例子中category专栏的重要性。每个类别都有一个单独的表是绝对可行的方法。

这是因为:

  1. 我们可以使用查找表通过强制外键来限制值
  2. 它使数据库更容易优化使用查找表连接数据表的查询
  3. 它更好地扩展:一个大的查找类别可以真正扭曲性能

在您的示例中,JobStatus和OrderStatus是单独的类别。适用于单独的实体。这就是为什么他们需要不同的查找表。在几个不同的数据表中共享相同的代码表甚至没有问题。当问题出现时,我们有一些单独的数据表(实体),其中某些状态是不合适的:这是将代码拆分成单独的查找表的时间。

编辑

我看到你编辑了你的帖子,引用了所有Anith的观点。我认为最重要的一点是关于约束的第一点。如果要将ORDERS.STATUS列限制为具有OrderStatus类别的值,则必须使用单独的表来强制执行外键。您的替代方案是:

  • 在ORDERS表上包含一个CodeCategory列,并对公共CODES表强制执行复合外键,该表现在需要一个唯一的键(Category,Code)。
  • 在检查约束中复制OrderStatus值
  • 不强制执行数据库中的值,并依赖应用程序的下拉列表来限制值。

从数据库的角度来看,所有这些选项都很糟糕。


8
投票

你已经有了正确的答案,所以这句话是额外的。

OTLT(一个真正的查找表)的一个大问题是,您最终将来自不同域的值放在同一列中,然后使用单独的列来消除歧义。

在您的示例中,您使用了每个状态描述旁边的数字。如果这些数字是数字代码,我认为它们必须是,那么你不希望值4,意思是“等待客户确认”在与值4相同的列中,意思是“已取消”。如果您这样做,那么您不能将此列用作您的一个真实查找表的PK。

如果你给你的一个真正的查找表另一列,称之为“CodeType”并使用“CodeType”和“Code”作为复合PK,你通过为每种代码类型设置一个单独的查找表,引入了比你介绍的更多的复杂性。

简短的回答是:不要将来自不同域的值放在同一列中。它总是比它节省更多的麻烦。

顺便说一句,可以创建一个视图,将所有单独的查找表组合成一个看似单个巨型查找表的视图。这在某些非常特殊的情况下非常有用。


4
投票

对于您需要的每个查找,您应该有一个单独的查找表,而不仅仅是一个。当你有一个时,它就成了系统的瓶颈,因为大多数查询可能需要加入表或查询该表。另外坦率地说,当你进入公司时,它会使系统更难维护和理解。

此外,您已经破坏了具有PK / FK关系的任何数据完整性。如果您有单独的表,FK意味着您不能输入任何不在查找表中的值。如果使用一个大表,则可以输入不适合该情况的值。我记得我工作的一个数据库,其中person_type的值对于某些记录是“是”。


1
投票

我认为您的订单状态示例并不符合本文中讨论的内容 - OrderStatus表似乎是作者认为您应该如何做到的。

有很多原因使得“查找表以结束所有查找表”是一种糟糕的方法,其中包括您无法定义关系,并且连接变得比应该更加困难。


1
投票

问题在于创建一个具有许多不同代码的中央表。您要么a)必须包含额外的列,以确保订单仅引用该表中的订单状态,或者b)您最终发送的作业和订单“无法修复并准备好接收”

编辑

现在你已经添加了Anith的理由和拒绝原因。同样,Anith所说的是为数据库中的所有查找值设置一个中央表。那么让我们看看2号:

“您必须将每种数据类型表示为具有此类通用查找表的字符串。”

如果我想表示另一种数据类型,我可以在其查找表中添加一列。

但是,如果有一个用于所有查找的中央表,那么您现在正在添加一个列,该列只应填充一个特定的查找操作。但是,您是否要添加强制执行此操作的CHECK约束(有效地创建NULL,但如果列上的Category ='X'约束,则为NOT NULL)。这可能会变成维护噩梦。

© www.soinside.com 2019 - 2024. All rights reserved.