关于数据库设计:MySQL ENUM类型与联接表

MySQL ENUM type vs join tables

我的要求

一个表需要维护一个状态列。

此列代表5种状态之一。

初始设计

我认为我可以使它成为一个整数列,并使用数值表示状态。

  • 0 =开始
  • 1 =跑步
  • 2 =坠毁
  • 3 =暂停
  • 4 =停止

由于我不希望我的应用程序维护从整数到其字符串描述的映射,因此我计划将它们放置在单独的状态描述表中(依赖于FK关系)。

然后我发现MySQL具有一个完全符合我的要求的ENUM类型。
除了直接依赖MySQL外,使用ENUM类型是否有陷阱?


  • 更改ENUM中的值集需要ALTER TABLE,这可能会导致表重组-一项非常昂贵的操作(如果仅在ENUM定义的末尾添加一个新值,则不会发生表重组。 ,但是如果您删除一个或更改顺序,则会进行表重组)。而更改查找表中的值集就像INSERT或DELETE一样简单。

  • 无法将其他属性与ENUM中的值相关联,例如哪些属性将被淘汰,哪些属性可以放入用户界面的下拉列表中。但是,查找表可以包含用于此类属性的其他列。

  • 查询ENUM以获得不同值的列表非常困难,基本上需要您从INFORMATION_SCHEMA查询数据类型定义,并从返回的BLOB中解析该列表。您可以从表中尝试SELECT DISTINCT status,但这只会获取当前正在使用的状态值,该值可能不是ENUM中的所有值。但是,如果将值保留在查找表中,则很容易查询,排序等。

正如您所知,我不是ENUM的忠实拥护者。 :-)

这同样适用于CHECK约束,这些约束只是将一列与一组固定值进行比较。尽管MySQL仍然不支持CHECK约束。

更新:MySQL 8.0.16现在实现了CHECK约束。


这里是关于枚举速度比较的文章。也许它提供了一些提示。
恕我直言,应仅限于固定字符串列表("是/否","儿童/成人")中使用,这种字符串将来有99%的可能性不变。


由于已经说明的原因,MySQL中的枚举不正确。
我可以添加以下事实:枚举不能确保在服务器端进行任何形式的验证。如果插入的行的值在enum定义中不存在,则将在DB中获得一个不错的NULL值,这取决于enum字段声明的NULL能力。

我关于tinyints的观点:

  • 枚举限制为65535个值
  • 如果您不需要超过256个值,tinyint将为每一行占用更少的空间,并且其行为更加"可预测"。

如果您的数据库中有大量数据(更多数据则具有RAM),并且ENUM值永远不会改变,那么我将使用ENUM而不是联接。它应该更快。
想想看,在连接的情况下,您需要在外键上建立索引,并在另一个表中建立主键上的索引。正如Riho所说,请参阅基准。


一个表将更易于国际化。但是数据库外部的类也将完全消失。
当不在业务逻辑中时,这种检查可能很难调试,并且通常不是数据库人员的责任。

作为优化,可能还为时过早;但是OP还是主要将其作为便利功能提出。

另请参见http://komlenic.com/244/8-reasons-why-mysqls-enum-data-type-is-evil/