根据Anith Sen的Five Simple Database Design Errors You Should Avoid,使用公共查找表来存储实体的可能状态是一个常见的错误。
编辑+答案:Anith文章中的数字没有很好的标注 - 我认为图1和图2都是糟糕设计的例子,而图2是好的设计。 P,在那里担心了一会儿。
我将在下面提出我的问题以供参考。
- “你失去了确保准确数据的手段;约束。通过将不同的实体组合到一个表中,你没有声明方法来约束某个类别的值。” 限制价值如何失去准确性?
- “您必须将每种数据类型表示为具有此类通用查找表的字符串。” 如果我想表示另一种数据类型,我可以在其查找表中添加一列。
- “你致力于坚强和随后的复杂性。” 怎么样?
- 第四,也是最后,您面临着物理实现问题。 我不明白为什么。
我不同意给出的大多数理由,并希望对我的错误进行客观批评?逻辑。
引用维修服务中的工作示例,其中许多可能的状态通常具有自然流程,让我们来看一个JobStatus
表:
可以说,这些状态中的一些可以归一化为像Couriered Items
,Completed Jobs
和Quotes
这样的表(具有待定/接受/拒绝状态),但这感觉就像不必要的模式复杂化。
另一个常见示例是用于限制订单状态的OrderStatus
表:
状态标题和描述在一个地方进行编辑,并且易于作为带有外键的下拉列表用于动态数据应用程序。这对我来说过去很有用。如果业务规则要求创建新的订单状态,我可以将其添加到OrderStatus
表,而无需重建我的代码。
为什么这是一个不好的做法?
编辑:我在我的问题中加入了Anith的理由,并试图保持客观。
--
Anith Sen建议反对的是所有查找代码都有一个查找表。这就是他的例子中category
专栏的重要性。每个类别都有一个单独的表是绝对可行的方法。
这是因为:
在您的示例中,JobStatus和OrderStatus是单独的类别。适用于单独的实体。这就是为什么他们需要不同的查找表。在几个不同的数据表中共享相同的代码表甚至没有问题。当问题出现时,我们有一些单独的数据表(实体),其中某些状态是不合适的:这是将代码拆分成单独的查找表的时间。
编辑
我看到你编辑了你的帖子,引用了所有Anith的观点。我认为最重要的一点是关于约束的第一点。如果要将ORDERS.STATUS列限制为具有OrderStatus类别的值,则必须使用单独的表来强制执行外键。您的替代方案是:
从数据库的角度来看,所有这些选项都很糟糕。
你已经有了正确的答案,所以这句话是额外的。
OTLT(一个真正的查找表)的一个大问题是,您最终将来自不同域的值放在同一列中,然后使用单独的列来消除歧义。
在您的示例中,您使用了每个状态描述旁边的数字。如果这些数字是数字代码,我认为它们必须是,那么你不希望值4,意思是“等待客户确认”在与值4相同的列中,意思是“已取消”。如果您这样做,那么您不能将此列用作您的一个真实查找表的PK。
如果你给你的一个真正的查找表另一列,称之为“CodeType”并使用“CodeType”和“Code”作为复合PK,你通过为每种代码类型设置一个单独的查找表,引入了比你介绍的更多的复杂性。
简短的回答是:不要将来自不同域的值放在同一列中。它总是比它节省更多的麻烦。
顺便说一句,可以创建一个视图,将所有单独的查找表组合成一个看似单个巨型查找表的视图。这在某些非常特殊的情况下非常有用。
对于您需要的每个查找,您应该有一个单独的查找表,而不仅仅是一个。当你有一个时,它就成了系统的瓶颈,因为大多数查询可能需要加入表或查询该表。另外坦率地说,当你进入公司时,它会使系统更难维护和理解。
此外,您已经破坏了具有PK / FK关系的任何数据完整性。如果您有单独的表,FK意味着您不能输入任何不在查找表中的值。如果使用一个大表,则可以输入不适合该情况的值。我记得我工作的一个数据库,其中person_type的值对于某些记录是“是”。
我认为您的订单状态示例并不符合本文中讨论的内容 - OrderStatus表似乎是作者认为您应该如何做到的。
有很多原因使得“查找表以结束所有查找表”是一种糟糕的方法,其中包括您无法定义关系,并且连接变得比应该更加困难。
问题在于创建一个具有许多不同代码的中央表。您要么a)必须包含额外的列,以确保订单仅引用该表中的订单状态,或者b)您最终发送的作业和订单“无法修复并准备好接收”
编辑
现在你已经添加了Anith的理由和拒绝原因。同样,Anith所说的是为数据库中的所有查找值设置一个中央表。那么让我们看看2号:
“您必须将每种数据类型表示为具有此类通用查找表的字符串。”
如果我想表示另一种数据类型,我可以在其查找表中添加一列。
但是,如果有一个用于所有查找的中央表,那么您现在正在添加一个列,该列只应填充一个特定的查找操作。但是,您是否要添加强制执行此操作的CHECK约束(有效地创建NULL,但如果列上的Category ='X'约束,则为NOT NULL)。这可能会变成维护噩梦。