是否可以用BOOLEAN属性替换参考(“类型”)实体FK,该属性表示该FK的可能值的完整集合?

时间:2012-12-21 00:04:22

标签: mysql data-modeling denormalization

在尝试通过删除连接(非规范化)来优化物理数据模型时,我选择获取用户可能为 CommEventPurposeType 指定的所有可能值,并将其实现为 CommEventPurpose ,最终丢弃 CommEventPurposeType 表及其 CommEventPurpose 中的FK。

我随后将使用CHECK约束来确保 CommEventPurpose 的每个实例只能有一个BOOLEAN属性为TRUE。

采用这种方法有哪些性能和空间权衡?

平台:MySQL

1 个答案:

答案 0 :(得分:0)

MySQL不强制执行CHECK约束。接受CHECK约束的语法,并将其作为文档保留在元数据中;但MySQL并没有强制执行它们。 (当然,你可以使用触发器自己强制执行这种类型的约束,同时使用BEFORE INSERT和BEFORE UPDATE触发器。)

但是如果你只想选择一个值,那么更好的选择就是ENUM数据类型的单个列。 ENUM数据类型仅允许分配预定义值列表中的一个值。 MySQL确实强制执行。

(当没有启用“strict”的SQL模式时,MySQL有点松懈;当分配了无效值而不是抛出异常时,MySQL会默默地替换“无值”占位符。)

与单独存储的布尔列相比,ENUM将在行中节省大量空间(但是,您计划实现布尔类型的存储,无论是单个字符还是TINYINT。)


您还询问了表现。

使用单个ENUM列,您将获得比使用单独存储的“布尔”列更好的性能 - 更短的行,更少的NULL指示符,每个块更多的行,仅一列的索引,而不是而不是在多列上,自动执行“仅一个”与调用存储程序(触发器)的开销。


就设计而言,使用ENUM数据类型与查找表的外键完全可接受,特别是,如果您通常会执行连接到查找表以检索字符串值在屏幕上显示或报告。

需要注意的是:只要你没有删除“实体”表,就可以删除“查找”表。通过“实体”表,我的意思是一个表格,其中包含代表“一个人,地点,事物,概念或事件的行,这些行可以唯一标识,对业务很重要。”

因此,例如,包含“打开”,“关闭”,“待定”,“取消”,“延迟”等的“状态”列是ENUM,的完美候选者,因为这些不是不可识别的“实体”,与我们真正关注的真实“实体”不同:客户,订单,发货,付款等。


后续

没有方便的机制来获取ENUM的有效值列表;根据我的经验,大多数开发人员更喜欢有一个表,他们可以按照正常模式运行“查询”查询。

我在“查询”表中添加的一件事是seq(序列)列,它指定了事物应该在下拉列表中显示的顺序(因为有时,要求是它们被列出按顺序排列,不是按字母顺序排列,也不容易从存储的字符串值中导出。)

我已经成功实现了ENUM数据类型来代替查找表的外键。它提供了一个稍微清晰的数据模型,(避免了图中绘制的外部干扰和不必要的关系线),并提高了应用程序的性能,因为它避免了JOIN到该查找表。从客户端来看,就select / insert / update而言,它就像VARCHAR列一样工作。