【问题标题】:MySQL ENUM VS INTMySQL ENUM VS INT
【发布时间】:2014-10-22 14:23:54
【问题描述】:

我有几个表的列可以是ENUM 类型或INT 类型。我倾向于总是使用整数类型,假设基于它执行搜索会更快。

例如,我的一个表有一个列:StatusType,它只能有 4 个可能的值:CompletedIn ProgressFailedTodo

我没有将上面存储为 ENUM 字符串,而是将它们存储为:

分别为1234。然后在我的 PHP 代码中,我有定义这些值的常量变量,如下所示:

define('COMPLETED', 1);
define('IN_PROGRESS', 2);
define('FAILED', 3);
define('TODO', 4);

现在我的问题是,我这样做是正确的还是应该将其更改为 ENUM 类型并使用字符串在查询中进行比较?我有许多其他列只能有一组最大 4-5 可能值。

【问题讨论】:

  • 为什么不将它们作为字符串存储在 varchar 列中呢?
  • @karlingen 在整数上搜索比在字符串上更快不是吗?
  • 你是如何使用这张桌子的?它是写得最多还是读得最多?
  • @JNevill 主要阅读。但它也写了很多。
  • 使用 php 枚举:php.net/manual/en/class.splenum.php,阅读其他答案以了解原因。

标签: php mysql


【解决方案1】:

枚举值在 MySQL 中看起来很酷,但我不喜欢它们。它们被限制为 255 个值,因此如果您决定添加更多值,那么您可能会遇到限制。此外,正如您所描述的,您需要将应用程序代码中的值与数据库中的值同步——这似乎有潜在的危险。

此外,它们使某些未来的变化更加困难。例如,其他数据库不支持枚举。而且,如果你想添加多语言支持,在数据库的数据类型定义中嵌入代码有点难以处理。

更标准的方法是一个或多个参考表,您可以在其中使用join 来获取值。您可以使用混合方法,在数据库中使用参考表。然后您可以将引用表加载到应用程序中,以获取从数字到字符串的映射,这样您就可以避免代码中的连接。

【讨论】:

  • 所以基本上还有另一个名为Statuses 的表并且有AUTO_INCREMENT ID 作为主键并且还引用StatusType 表? Statuses 也将有一个字符串来表示它的状态。现在这听起来像是一个很好的解决方案,但说我想选择All Completed 记录。我仍然需要与参考表中的字符串进行比较,对吗?
  • 我也在写同样的东西。将您的 StatusType_Code/StatusType_Desc 存储在单独的表中。在大表中使用代码,仅在需要文本值时调用单独的文本表。
  • @GGio - 事实上,是否使用AUTO_INCREMENT 实际上与主题无关(尽管我建议不要这样做,因为设置的值似乎不是特别动态)。跨度>
  • 同样在 Auto_Increment 上,您可能会发现您希望将来以某种方式对文本/描述进行编号。您可能会发现将其编号为 10、20、30、40 很有价值,以防您将来想要排序并将新值添加到排序中而不重新编号所有内容。 AutoIncrement 很好,但在这里有点矫枉过正,而且可能会受到限制。
【解决方案2】:

你说对了一半。从性能的角度来看,枚举非常糟糕:MySQL Enum performance advantage?

也就是说,将INTs 的定义绑定到您的代码也不是一件好事。理想情况下,如果您要遵循正确的数据规范化模式,您也可以在数据库中的另一个表中定义 INTs 的值,并将定义的索引用作分配的值。

见:http://en.wikipedia.org/wiki/Database_normalization#Normal_forms

这样做的原因是数据是可移植的,并且无需代码库读取即可使用(您可以通过执行连接轻松地将 CSV 转储为 Excel)。

神速。

示例 SQL:

SELECT *, state.name AS state FROM students
JOIN states ON student.state_id = states.id

只是为了获取州名。

或过滤:

SELECT * FROM students
JOIN states ON student.state_id = states.id
WHERE state.name = 'Maine' OR state.code = 'ME'

是的,奇怪的例子,但想法是 INTs 是 TINY,而 VARCHAR 是...变量...存储 'Maine' 而不是 '16' 加起来超过数百万行。此外,INT 上的索引比 VARCHAR 快得多,因此您的查找速度会快得多。特别是如果您事先知道该数字并在没有JOIN 的情况下构建您的查询。作为一种常见做法,这是不可取的,但如果您想更快地进行某些操作,并且可以确保假设值的有效性,则可以这样做。

【讨论】:

  • 所以说我想选择所有Completed 记录。我会有这样的东西:SELECT * FROM StatusType INNER JOIN Statuses ON SsID = StID WHERE SsName = 'Completed' 这仍然与字符串相比不是吗? SsName 将是参考表中的列
  • @GGio,是的,这将在字符串上进行比较,但它正在比较的表只有 4 或 5 条记录。然后它将使用 ID 连接回您的大表,因此您在大表上的读取仍然很快。这里的任何速度损失都只是​​由于 JOIN。考虑重写您的示例 SQL 语句以在 where 中使用 ID,这样您就可以避免连接。仅当您确实需要将值带入前端以供用户查看时才使用键/值表。
猜你喜欢
  • 2015-11-24
  • 1970-01-01
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 2017-08-25
  • 1970-01-01
相关资源
最近更新 更多