1

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

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

采用这种方法的性能和空间权衡是什么?

平台:MySQL

4

1 回答 1

0

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

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

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

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


您还询问了性能。

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


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

需要注意的是:只要您不消除“实体”表,就可以消除“查找”表。“实体”表是指包含代表“可以唯一标识且对业务很重要的人、地点、事物、概念或事件”的行的表。

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


跟进

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

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

我已经成功地实现了ENUM数据类型来代替查找表的外键。它提供了一个稍微干净的数据模型(避免了在图表上绘制的额外分散注意力和不必要的关系线),并提高了应用程序的性能,因为它避免了对那个查找表的 JOIN。从客户端来看,它就像一个 VARCHAR 列,在选择/插入/更新方面。

于 2012-12-21T00:14:46.973 回答