在 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可能会给您带来巨大的性能优势。

此论点适用于 ...INTFLOATDOUBLEDECIMAL(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%)。

【讨论】:

谢谢,那么 MySQL MEDIUMINT(3 字节)整数呢?它会导致 CPU 做额外的工作来对齐寄存器上的数据吗?这就是我被告知here @Accountantم - 我的背景使我非常了解“单词对齐”。但是,我声称,在这种情况下,它确实是微不足道的。我在我的答案中添加了一堆。

以上是关于在 MySQL 中应该避免 MEDIUMINT 吗?的主要内容,如果未能解决你的问题,请参考以下文章

mediumint 在mysql 中是啥类型

MySQL 中的 tinyint、smallint、mediumint、bigint 和 int 有啥区别?

MySQL整数数据类型mediumint

mediumint(10) 中的数字表示啥? [复制]

我应该避免在减少中使用对象传播吗?

TINYINT,SMALLINT,MEDIUMINT,INT,INTEGER,BIGINT;text,longtext,mediumtext,ENUM,SET等字段类型区别