MySQL:Enum与带索引的Varchar

MySQL:Enum与带索引的Varchar,mysql,database,indexing,database-design,sqldatatypes,Mysql,Database,Indexing,Database Design,Sqldatatypes,假设我需要创建一个表,其中一列的值来自这个有限且永不更改的集合: “全部”、“本地”、“qa”、“暂存”和“生产” 在这种情况下使用enum数据类型看起来是一个合适的解决方案,但在阅读了internet上的一些其他线程后,我觉得不鼓励使用它。因此,如果我想创建一个查找表并且保持evn和name的组合的唯一性也是一个要求,那么在ENUM类型的列和VARCHAR类型但在其上创建索引的列之间,我的最佳选择是什么 还考虑到此表中的插入很少,我们希望此特定查询执行得更快: SELECT `enabled`

假设我需要创建一个表,其中一列的值来自这个有限且永不更改的集合: “全部”、“本地”、“qa”、“暂存”和“生产”

在这种情况下使用
enum
数据类型看起来是一个合适的解决方案,但在阅读了internet上的一些其他线程后,我觉得不鼓励使用它。因此,如果我想创建一个查找表并且保持
evn
name
的组合的唯一性也是一个要求,那么在ENUM类型的列和VARCHAR类型但在其上创建索引的列之间,我的最佳选择是什么

还考虑到此表中的插入很少,我们希望此特定查询执行得更快:

SELECT `enabled` FROM `features`
WHERE `name` = 'some_featuere'
AND `env` IN('all', 'qa')
ORDER BY `enabled` ASC limit 1;
哪一种设计更好?为什么

CREATE TABLE `features` (
  `id` INTEGER  NOT NULL AUTO_INCREMENT,
  `name` VARCHAR (50) NOT NULL,
  `env` ENUM('all', 'local', 'qa', 'staging', 'production') NOT NULL,
  `enabled` TINYINT(1) DEFAULT 0,
  `created_at` DATETIME,
  `updated_at` DATETIME,

  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_unq_features_name_env` (`name`,`env`)
);


对您的问题的简短回答是“两者都不是”,因为在这两种情况下,您的查询都会使用name/env上的索引。然而,如果我必须解决一个问题,我会选择VARCHAR而不是ENUM作为两个缺点中的较小者,但我认为您的方法可能存在一些其他问题

首先,VARCHAR选项只会重复那篇文章中提到的ENUM的一个问题(即添加属性或相关数据),同时可能会失去从ENUM获得的唯一优势,即数据完整性。您可以通过查找获得数据完整性,而不必使用枚举

其次,您可能会关注查询中不存在的性能问题。它多久运行一次?有多慢?目前,您在
NAME
/
ENV
上有一个索引,我想不出加快查询速度的唯一方法是使用一个覆盖索引来包含
ENABLED
,但我怀疑它是一个性能杀手,我怀疑您在加入查找表时看到的差别很小

第三,“全部”作为选项没有什么意义,除非一个特性一次只能部署在一个环境中,或者同时部署在所有环境中。如果这不是真的,那么无论何时您想要应用“all”选项,都必须删除与功能名称相关的所有其他记录“全部”还将防止在不同环境中选择性地启用/禁用功能,或单独记录创建/更新事件。这就引入了不需要存在的数据管理问题


第四,虽然列
ID
NAME
CREATED\u AT
UPDATED\u AT
都是与特征直接相关的属性。列
ENV
ENABLED
与该功能的部署位置和方式有关。乍一看,这建议将这些数据存储在一个完全独立的表中(可能在处创建
并在
处更新
以指示它们首次部署和最后更新的时间)。我个人认为Feature、Environment和Feature_Environment是单独的表,带有从Feature_Environment到其他两个的外键。

您的问题的简短答案是“两者都不是”,因为您的查询在这两种情况下都会使用name/env上的索引。然而,如果我必须解决一个问题,我会选择VARCHAR而不是ENUM作为两个缺点中的较小者,但我认为您的方法可能存在一些其他问题

首先,VARCHAR选项只会重复那篇文章中提到的ENUM的一个问题(即添加属性或相关数据),同时可能会失去从ENUM获得的唯一优势,即数据完整性。您可以通过查找获得数据完整性,而不必使用枚举

其次,您可能会关注查询中不存在的性能问题。它多久运行一次?有多慢?目前,您在
NAME
/
ENV
上有一个索引,我想不出加快查询速度的唯一方法是使用一个覆盖索引来包含
ENABLED
,但我怀疑它是一个性能杀手,我怀疑您在加入查找表时看到的差别很小

第三,“全部”作为选项没有什么意义,除非一个特性一次只能部署在一个环境中,或者同时部署在所有环境中。如果这不是真的,那么无论何时您想要应用“all”选项,都必须删除与功能名称相关的所有其他记录“全部”还将防止在不同环境中选择性地启用/禁用功能,或单独记录创建/更新事件。这就引入了不需要存在的数据管理问题


第四,虽然列
ID
NAME
CREATED\u AT
UPDATED\u AT
都是与特征直接相关的属性。列
ENV
ENABLED
与该功能的部署位置和方式有关。乍一看,这建议将这些数据存储在一个完全独立的表中(可能在
处创建
并在
处更新
以指示它们首次部署和最后更新的时间)。我个人认为Feature、Environment和Feature_Environment是单独的表,外键从Feature_Environment到其他两个表。

支持枚举和反对枚举的派系之间正在进行一场“宗教”战争。你读过一篇“反”的文章。但是那篇文章中的许多“邪恶”可能不适用于你的情况

如果删除当前主键
id
,并将其替换为

PRIMARY KEY(name, env)
之后,不需要二级索引

您所拥有的内容需要在一个辅助键中进行查找,然后进入PK以获得第三列。之后,分类并交付一行

更改PK可以避免额外的查找。这一变化不应该有“负面影响”

如果表中有数百万行,则可能有1000行
PRIMARY KEY(name, env)
    (   SELECT  `enabled`
            FROM  `features`
            WHERE  `name` = 'some_featuere'
              AND  `env` = 'all'
            ORDER BY  `enabled` ASC
            limit  1
    )
    UNION DISTINCT
    (  SELECT  `enabled`
            FROM  `features`
            WHERE  `name` = 'some_featuere'
              AND  `env` = 'qa'
            ORDER BY  `enabled` ASC
            limit  1 
    )
    ORDER BY  `enabled`
    LIMIT  1;
`env` SET('local', 'qa', 'staging', 'production') NOT NULL,
PRIMARY KEY (`name`)
AND `env` IN('all', 'qa')
AND env = 'qa'