在 MySQL 中应该避免 MEDIUMINT 吗?
Posted
技术标签:
【中文标题】在 MySQL 中应该避免 MEDIUMINT 吗?【英文标题】:Should MEDIUMINT be avoided in MySQL? 【发布时间】:2014-10-05 00:30:49 【问题描述】:我在以下博客文章中看到一条评论,建议不要使用MEDIUMINT
:
即使在 mysql 中,也不要使用 [24bit INT]。它很笨,而且很慢,实现它的代码令人毛骨悚然。
4294967295 and MySQL INT(20) Syntax Blows
Stack Overflow 上的回答还指出,SQL Server、PostgreSQL 和 DB2 不支持MEDIUMINT
:
What is the difference between tinyint, smallint, mediumint, bigint and int in MySQL?
应该避免使用MEDIUMINT
,还是应该在它最能代表我存储的数据的情况下继续使用它?
【问题讨论】:
这是虚假的经济。现代处理器的自然宽度是 32 位或 64 位,数据库必须付出额外的努力来强制执行 24 位整数宽度。 @JimGarrison 我真的怀疑这在很大程度上是一个因素。它可以存储为内存中的 32 位(或不存储,但这并不重要),也可以存储在 24 位的记录中。 (在 int 上最多可节省 25% 的空间。) 【参考方案1】:InnoDB 将 MEDIUMINT 存储为三个字节的值。 但是当 MySQL 必须进行任何计算时,三个字节 MEDIUMINT 会转换为八个字节 unsigned long int(我假设现在没有人在 32 位上运行 MySQL)。
有利也有弊,但你明白“它很笨,而且很慢,实现它的代码令人毛骨悚然”的推理不是技术性的,对吧?
当磁盘上的数据大小至关重要时,我会说 MEDIUMINT 是有意义的。 IE。当一个表有如此多的记录时,即使一个字节的差异(4 字节 INT 与 3 字节 MEDIUMINT)也意味着很多。这是相当罕见的情况,但有可能。
mach_read_from_3 和 mach_read_from_4 - InnoDB 用来从 InnoDB 记录中读取数字的原语是相似的。他们都返回 ulint。我敢打赌,您不会注意到任何工作负载的差异。
看一下代码:
ulint
mach_read_from_3(
/*=============*/
const byte* b) /*!< in: pointer to 3 bytes */
ut_ad(b);
return( ((ulint)(b[0]) << 16)
| ((ulint)(b[1]) << 8)
| (ulint)(b[2])
);
你认为它比这慢得多吗?
ulint
mach_read_from_4(
/*=============*/
const byte* b) /*!< in: pointer to four bytes */
ut_ad(b);
return( ((ulint)(b[0]) << 24)
| ((ulint)(b[1]) << 16)
| ((ulint)(b[2]) << 8)
| (ulint)(b[3])
);
【讨论】:
好的,谢谢。我想我想确认一下 MySQL 在内部处理 mediumint 的方式是否有什么特别不好的地方,或者它是否真的不标准,应该避免。如果它适合存储的数据,听起来就可以使用。 嗨,你的意思是,如果我在 MySQL 中使用这个:min(MEDIUMINTField)
,结果将是 8 个字节,例如,在 java 中,我需要一个 long
类型变量?
由客户端库决定结果使用哪种类型。【参考方案2】:
在宏伟的计划中,获取一行是很大的成本。简单的函数、表达式,更不用说数据格式,对于查询所需的时间来说是无关紧要的。
另一方面,如果您的数据集太大而无法保持缓存,那么获取行的 I/O 开销就更大了。一个粗略的经验法则是,非缓存行的耗时是缓存行的 10 倍。因此,缩小数据集(例如使用更小的 *INT
)可能会给您带来巨大的性能优势。
此论点适用于 ...INT
、FLOAT
与 DOUBLE
、DECIMAL(m,n)
、DATETIME(n)
等([VAR]CHAR/BINARY(...)
和 TEXT/BLOB
需要进行不同的讨论。)
对于那些有汇编语言背景的人...
表格可能混合了数字和字符串,从而阻碍了“对齐”值的尝试。 MySQL 一直处理各种硬件(大/小端、16/32/64 位)具有二进制兼容性。请注意@akuzminsky 提供的代码如何避免对齐和字节序问题。如果硬件只有 16 位,它可以让编译器处理 32 位问题。 测试特殊情况的代码可能会超过简单地编写通用代码。 我们谈论的时间通常不到总行处理时间的 1%。因此,编写代码的唯一合理方法是在字节级别工作,忽略寄存器大小并假设所有值都未对齐。
对于优化,按重要性排序:
-
计算磁盘命中数。触摸磁盘绝对是查询中成本最高的部分。
计算触摸的行数。查找一行(通过 BTree 等)需要一些 CPU。但是,请注意,很少有安装受 CPU 限制;那些往往有较差的索引。 (经验法则:一个 InnoDB 数据或索引块中通常有 100 行。)
现在才开始解析行。
经验法则:如果试验性优化没有(通过粗略计算)产生 10% 的改进,请不要在这上面浪费时间。而是寻求一些更大的改进。例如,索引和汇总表通常提供 10 倍(不仅仅是 10%)。
【讨论】:
谢谢,那么 MySQLMEDIUMINT
(3 字节)整数呢?它会导致 CPU 做额外的工作来对齐寄存器上的数据吗?这就是我被告知here
@Accountantم - 我的背景使我非常了解“单词对齐”。但是,我声称,在这种情况下,它确实是微不足道的。我在我的答案中添加了一堆。以上是关于在 MySQL 中应该避免 MEDIUMINT 吗?的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 中的 tinyint、smallint、mediumint、bigint 和 int 有啥区别?
TINYINT,SMALLINT,MEDIUMINT,INT,INTEGER,BIGINT;text,longtext,mediumtext,ENUM,SET等字段类型区别