在尝试通过删除连接(非规范化)来优化物理数据模型时,我选择采用用户可能为 CommEventPurposeType 指定的所有可能值,将它们实现为 中的 BOOLEAN 属性>CommEventPurpose,将最终丢弃 CommEventPurposeType 表及其在 CommEventPurpose 中的 FK。
我随后将使用 CHECK 约束来确保对于 CommEventPurpose 的每个实例只有一个 BOOLEAN 属性可以为真。
采用这种方法的性能和空间权衡是什么?
平台:MySQL
最佳答案
MySQL 不强制执行CHECK
约束。 CHECK
约束的语法被接受,并作为文档保留在元数据中;但 MySQL 不强制执行它们。 (当然,您可以使用触发器来自己实现这种类型的约束,同时使用 BEFORE INSERT 和 BEFORE UPDATE 触发器。)
但如果您只想选择一个值,那么更好的选择是 ENUM
数据类型的单列。 ENUM
数据类型只允许分配预定义值列表中的一个值。 MySQL 确实强制执行了这一点。
(当“strict”的SQL模式没有启用时,MySQL有点松懈;当分配了一个无效值时,MySQL并没有抛出异常,而是默默地替换了一个“无值”占位符。)
与单独存储的 bool 列相比,ENUM 将在行中节省大量空间(但是您计划实现 bool 类型的存储,无论是单个字符还是 TINYINT。)
您还询问了性能。
使用单个 ENUM
列会比使用单独存储的“ bool ”列获得更好的性能 -- 更短的行、更少的 NULL 指示符、每个 block 更多的行、仅一个索引列,而不是在多个列上,自动执行“只有一个”与调用存储程序(触发器)的开销。
就设计而言,与查找表的外键相比,使用 ENUM
数据类型是完全可以接受的,特别是如果您通常会执行与查找表的连接以检索要显示在屏幕或报告上的字符串值。
需要注意的是:只要不删除“实体”表,就可以删除“查找”表。我所说的“实体”表是指包含行的表,这些行代表“可以唯一标识且对业务很重要的人、地点、事物、概念或事件。”
因此,例如,包含“打开”、“关闭”、“待定”、“取消”、“延迟”等的“状态”列非常适合 ENUM,
因为这些不是单独可识别的“实体”,不像我们真正关心的真实“实体”:客户、订单、发货、付款等。
跟进
没有方便的机制来获取 ENUM 的有效值列表;根据我的经验,大多数开发人员更喜欢有一个表,他们可以按照他们的正常模式对其运行“查找”查询。
我在“查找”表中添加的一件事是 seq
(序列)列,它指定了事物在下拉列表中的显示顺序(因为有时,要求是它们以非字母顺序列出,并且不容易从存储的字符串值中导出。)
我已经成功地实现了 ENUM
数据类型来代替查找表的外键。它提供了一个稍微干净的数据模型,(避免在图表上画出多余的分散注意力和不必要的关系线),并提高了应用程序的性能,因为它避免了连接到该查找表。从客户端来看,就选择/插入/更新而言,它就像 VARCHAR 列一样工作。
关于mysql - 可以用表示该 FK 的完整可能值集的 BOOLEAN 属性替换引用 ("Type") 实体 FK 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13982437/