假设,我需要创建一个表,其中一列将具有来自此有限且永不改变的集合的值: '所有','本地' qa',' staging'和' production'。
在这种情况下使用enum
数据类型看起来是一个合适的解决方案,但在阅读了this article和互联网上的其他一些主题后,我不鼓励使用它。所以,如果我不想创建一个查找表和保持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`)
);
OR
CREATE TABLE `features` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR (50) NOT NULL,
`env` VARCHAR(10) NOT NULL,
`enabled` TINYINT(1) DEFAULT 0,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `idx_features_env` (`env`),
UNIQUE KEY `idx_unq_features_name_env` (`name`,`env`)
);
答案 0 :(得分:1)
您的问题的简短回答是“不”,因为您的查询将在两个方案中使用name / env上的索引。但是,如果我不得不选择其中一个,那么我会选择VARCHAR而不是ENUM作为两个邪恶的较小但我认为你的方法可能还有其他一些问题。
首先,VARCHAR选项只会复制该文章中提到的ENUM问题(即添加属性或相关数据),同时可能会损失您从ENUM获得的唯一优势,即数据完整性。您可以通过查找获得数据完整性,而无需ENUM的恶意。
其次,您可能会关注查询不存在的性能问题。它多久运行一次?它有多慢?就目前而言,你有一个NAME
/ ENV
的索引,我想不到加速查询的唯一方法是覆盖索引,包括ENABLED
,但我怀疑这是一个性能杀手,我怀疑你看到加入查询表的差别很小。
第三,除非一个功能一次只能在一个环境中或同时在所有环境中部署,否则'ALL'作为一个选项毫无意义。如果不成立,则无论何时要应用“ALL”选项,都必须删除与功能名称相关的所有其他记录。 “ALL”还可以防止在不同环境中有选择地启用/禁用功能或单独记录创建/更新事件。这引入了不需要存在的数据管理问题。
第四,虽然列ID
,NAME
,CREATED_AT
,UPDATED_AT
都是看似直接与功能相关的属性。列ENV
和ENABLED
与部署功能的位置和方式有关。乍一看,这表明将这些数据存储在一个完全独立的表中(可能包含CREATED_AT
和UPDATED_AT
,以指示它们何时首次部署和上次更新)。我个人将Feature,Environment和Feature_Environment作为单独的表与Feature_Environment中的外键一起使用到其他两个表。
答案 1 :(得分:1)
有一个宗教信仰'亲ENUM和反ENUM派系之间的战争。你已经阅读了其中一个' anti'文章。但许多"邪恶"在那篇文章中可能不适用于你的情况。
您的查询可以通过摆脱目前的PK id
并将其替换为
PRIMARY KEY(name, env)
之后,不需要二级索引。
您需要在辅助密钥中查找,然后进入PK以获取第三列。之后,排序并交付一行。
更改PK可避免额外查找。并且应该没有"缺点"改变。
如果表中有数百万行,并且您可能要求每个env
值的数千个候选者,那么这将更快,因为它不会收集"数千&# 34;行,排序,只提供一个。相反,它会获得两行并从中挑选:
( 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;
是的,ORDER BY
和LIMIT
会重复出现。我不推荐这个OR
- > UNION
用于小型数据集,因为有许多步骤,每个步骤都有开销。
无论您使用ENUM还是其他方法,我的答案都适用。它确实假设InnoDB。
答案 2 :(得分:1)
这是一个不同的答案 - 使用SET
数据类型。
以下是表格更改:
`env` SET('local', 'qa', 'staging', 'production') NOT NULL,
PRIMARY KEY (`name`)
没有辅助密钥,没有'all'
,每name
只有一行。
然而,测试变得更加混乱。还是变得更简单?那是
AND `env` IN('all', 'qa')
- >
AND env = 'qa'
因为测试现在只有一件事。凌乱的all
已经消失了。
如果所有这些都符合业务逻辑,则表和查询更简单,更快。
如果我对业务逻辑有误,请详细说明。可能有办法拯救此答案(使用SET
而不是IN
)。