哪个更快: char(1) 或 tinyint(1) ?为啥?
Posted
技术标签:
【中文标题】哪个更快: char(1) 或 tinyint(1) ?为啥?【英文标题】:Which is faster: char(1) or tinyint(1) ? Why?哪个更快: char(1) 或 tinyint(1) ?为什么? 【发布时间】:2011-01-02 16:02:15 【问题描述】:我的平台:
我的情况:
我遇到了一种情况,我需要在表格的一个列中存储用户选择的值。现在我的选择是:
-
将列声明为 char(1) 并将值存储为“y”或“n”
或者将 Column 声明为 tinyint(1) 并将值存储为 1 或 0
如此声明的该列也可以被索引以在应用程序中使用。
我的问题:
所以我想知道,以上两种是哪一种:
在访问该列时导致查询速度更快(为简单起见,请不要混合其他查询或访问其他列)。
是存储和访问数据的最有效方式吗?为什么?
如果列被索引,访问速度如何变化?
我的理解是,由于 char(1) 和 tinyint(1) 只占用 1 个字节空间,在这种情况下存储空间不会成为问题。那么剩下的就是访问速度了。据我所知,数字索引比其他任何东西都更快、更有效。 但我认为,这里的案子很难决定。肯定想听听您在这方面的经验。
提前谢谢你。
【问题讨论】:
分析它并让我们知道结果。 一个错误的二分法,还有enum('1','0')
(例如)。
这个问题与php无关所以我删除了php标签
用两个可能的值索引一个字段是毫无价值的。
@recursive 列的类型对其索引的适用性几乎没有影响。如果将列放在WHERE
子句中并且没有索引,则无论类型如何,它都必须进行全表扫描。
【参考方案1】:
Rate insert tinyint(1) insert char(1) insert enum('y', 'n')
insert tinyint(1) 207/s -- -1% -20%
insert char(1) 210/s 1% -- -19%
insert enum('y', 'n') 259/s 25% 23% --
Rate insert char(1) insert tinyint(1) insert enum('y', 'n')
insert char(1) 221/s -- -1% -13%
insert tinyint(1) 222/s 1% -- -13%
insert enum('y', 'n') 254/s 15% 14% --
Rate insert tinyint(1) insert char(1) insert enum('y', 'n')
insert tinyint(1) 234/s -- -3% -5%
insert char(1) 242/s 3% -- -2%
insert enum('y', 'n') 248/s 6% 2% --
Rate insert enum('y', 'n') insert tinyint(1) insert char(1)
insert enum('y', 'n') 189/s -- -6% -19%
insert tinyint(1) 201/s 7% -- -14%
insert char(1) 234/s 24% 16% --
Rate insert char(1) insert enum('y', 'n') insert tinyint(1)
insert char(1) 204/s -- -4% -8%
insert enum('y', 'n') 213/s 4% -- -4%
insert tinyint(1) 222/s 9% 4% --
似乎在大多数情况下,enum('y', 'n')
插入速度更快。
Rate select char(1) select tinyint(1) select enum('y', 'n')
select char(1) 188/s -- -7% -8%
select tinyint(1) 203/s 8% -- -1%
select enum('y', 'n') 204/s 9% 1% --
Rate select char(1) select tinyint(1) select enum('y', 'n')
select char(1) 178/s -- -25% -27%
select tinyint(1) 236/s 33% -- -3%
select enum('y', 'n') 244/s 37% 3% --
Rate select char(1) select tinyint(1) select enum('y', 'n')
select char(1) 183/s -- -16% -21%
select tinyint(1) 219/s 20% -- -6%
select enum('y', 'n') 233/s 27% 6% --
Rate select tinyint(1) select char(1) select enum('y', 'n')
select tinyint(1) 217/s -- -1% -4%
select char(1) 221/s 1% -- -2%
select enum('y', 'n') 226/s 4% 2% --
Rate select char(1) select tinyint(1) select enum('y', 'n')
select char(1) 179/s -- -14% -20%
select tinyint(1) 208/s 17% -- -7%
select enum('y', 'n') 224/s 25% 7% --
选择似乎也是enum
。代码可以是found here
【讨论】:
+1 @gms8994 非常感谢您提供的统计数据。更深入地了解速度。您是否可以让我们知道是否还有其他工具可以产生与上述相同的结果?再次感谢。 @Devner 我不知道。我专门为这个问题写了这个,但你可以查看响应中链接的 GitHub 页面。 你用的是什么版本的mysql? 很想看看使用枚举对'y'和null而不是enum('y', 'n')
的性能【参考方案2】:
我认为您应该使用ENUM('n','y')
创建列。 Mysql 以最佳方式存储这种类型。它还将帮助您在字段中仅存储允许的值。
您还可以在不影响性能的情况下使其更加人性化ENUM('no','yes')
。因为字符串 'no'
和 'yes'
在每个 ENUM
定义中只存储一次。 Mysql 只存储每行值的索引。
还要注意按ENUM
列排序:
ENUM 值根据枚举成员在列规范中列出的顺序进行排序。 (换句话说,ENUM 值是根据它们的索引号排序的。)例如,对于 ENUM('a', 'b'),'a' 在 'b' 之前排序,但对于 ENUM,'b' 在 'a' 之前排序('b', 'a')。
【讨论】:
很久以前,我和 OP 有同样的问题,我对它进行了基准测试,以找到 enum 三个选项中最快和最有效的。只要确保你不像我那样使用 enum('0', '1') ——你最终会想知道为什么 UPDATE X SET Y = 0;不起作用(你需要单引号)。 +1 为兰登。这是您指定的一个非常独特的点。直到现在我才知道。所以这意味着如果我们使用 enum('0', '1'),我们的查询必须有 UPDATE X SET Y = '0';那是对的吗? @Ivan 如果我是对的,ENUM('n','y') 占用与 ENUM('no','yes') 相同的空间。我说的对吗? @Devner 是的,空间使用情况是一样的,因为除了 ''、'no' 和 'yes' 之外,您不能添加任何值。 Mysql 只存储每行值的索引,而不是字符串。字符串 'no' 和 'yes' 在表定义中只存储一次。 @Devner:所有枚举值都有数字索引,从 1 开始(0 是表示空字符串的特殊值)。您可以使用这些索引来查询和设置值,但正如手册中所说:“由于这些原因,不建议使用看起来像数字的枚举值定义 ENUM 列,因为这很容易变得混乱。” [dev.mysql.com/doc/refman/5.1/en/enum.html](不要将这些数字索引与真正的列索引混淆,没有更好的词来区分它们) 枚举是devil的工作!【参考方案3】:要确定它,您应该对其进行基准测试。或者知道从整个项目的宏观角度来看,这可能并不重要。
Char 列具有编码和排序规则,比较它们可能涉及编码之间的不必要切换,所以我的猜测是 int 会更快。出于同样的原因,我认为更新 int 列上的索引也更快。但同样,这并不重要。
CHAR
可以占用多个字节,具体取决于您选择的字符集和表选项。有些字符可能需要三个字节来编码,因此 MySQL 有时会保留该空间,即使您只使用 y
和 n
。
【讨论】:
+1 表示“但同样,这并不重要。”我也在想同样的事情。差异可能可以忽略不计。 @Jan 你说的对我来说很有意义。所以说如果我使用 enum('n', 'y'),编码和比较滞后之间的切换是否仍然适用?使用 INNODB VS MyISAM 会有什么不同? @Devner:是的,因为枚举列是用编码和排序规则定义的,我认为这会对性能产生影响。我不知道 InnoDB 和 MyISAM 之间的区别,只是说明和 InnoDB 选项会影响字符存储 [dev.mysql.com/doc/refman/5.1/en/data-size.html]【参考方案4】: TINYINT 1 Byte
CHAR(M) M Bytes, 0 <= M <= 255
有什么不同吗?
【讨论】:
【参考方案5】:虽然我的直觉是 TINYINT 上的索引会比 CHAR(1) 上的索引更快,因为没有字符串处理开销(排序规则、空格等),但我没有任何事实来支持这一点。我的猜测是没有值得担心的显着性能差异。
但是,因为您使用的是 PHP,所以存储为 TINYINT 更有意义。使用 1/0 值等同于使用 true
和 false
,即使它们作为字符串返回给 PHP,也可以这样处理。您可以简单地使用 if ($record['field'])
将结果作为布尔检查,而不是一直在 'y' 和 'n' 之间转换。
【讨论】:
+1 @Zombat 这是有道理的。我认为使用数字确实可以简化应用程序中 PHP 代码的处理。【参考方案6】:如果在 MySQL 中创建表时指定类型 BOOL
或 BOOLEAN
作为列类型,则创建列类型为 TINYINT(1)
。大概这是两者中较快的一个。
Documentation
还有:
我们打算实现完整的布尔值 类型处理,按照 标准 SQL,未来的 MySQL 释放。
【讨论】:
【参考方案7】:使用 tinyint 是更标准的做法,可以让您更轻松地检查字段的值。
// Using tinyint 0 and 1, you can do this:
if($row['admin'])
// user is admin
// Using char y and n, you will have to do this:
if($row['admin'] == 'y')
// user is admin
我不是 MySQL 内部工作的专家,但直觉上觉得检索和排序整数字段比字符字段快(我只是觉得 'a' > 'z' 比 0 更工作> 1),并且从计算的角度来看似乎更加熟悉,其中 0 和 1 是标准的开/关标志。所以整数的存储似乎更好,感觉更好,并且更容易在代码逻辑中使用。 0/1 显然是我的赢家。
您可能还注意到,在某种程度上,这也是 MySQL 的官方立场,来自their documentation:
BOOL, BOOLEAN:这些类型是 微小的(1)。零值是 认为是假的。非零值是 认为是真的。
如果 MySQL 将 TINYINT(1) 等同于 BOOLEAN,这似乎是可行的方法。
【讨论】:
也许有这样的检查是件好事? IDE,让我解释一下.... require_once("./Permissions.php"); ... if( $row['permissions'] === Permissions::ADMIN ) // user is admin 这不仅有利于代码的可读性,而且使用静态属性来引用一个值可以缩短编译时间检查拼写错误,并且在使用预测性 IDE 时,它将帮助您快速编写代码。此示例为您提供了多级权限,但我认为可读性和可维护性是开发大型项目的关键,所以我完全赞成。 @Gary 感谢您的评论,但我无法判断您是提倡使用 0 和 1 还是不使用它。我只是觉得您的编程实践与我的不同,所以请多多包涵,因为我可能需要更多时间来理解您的意思。【参考方案8】:他们都将如此接近,这并不重要。如果您觉得必须在 SO 上提出这个问题,那么您就过度优化了。使用最符合逻辑的那个。
【讨论】:
@Dave 感谢您的评论。以上是关于哪个更快: char(1) 或 tinyint(1) ?为啥?的主要内容,如果未能解决你的问题,请参考以下文章