如果将 INT 列更改为 MEDIUMINT,我将节省多少大小?

How much size I will save if changed INT column to MEDIUMINT?

我正在学习如何通过为列重新选择正确的数据类型来优化我的数据库,我想知道如果我选择 MEDIUMINT(3 字节)而不是 [,我将节省多少大小=11=](4 字节)

AFAIK - 如果我错了请纠正我 - 我需要数据库大小尽可能小以适应 RAM 以减少硬盘请求。数据库的大小包括 tables 大小 + 索引大小

考虑到我有一个包含 10'000'000 行和 B-Tree 索引的 INT 列,如果我将列的数据类型从INTMEDIUMINT

注意:我知道 MySQL 不会减少磁盘上的实际大小,除非我 OPTIMIZE TABLE

编辑:我的情况是,我将很快完成我人生中的第一个 重要 系统 - 这是一个我计划在阿拉伯地区市场销售的 ERP 系统 - 。计划 1、2、3、4 数据库应该分别约为 2GB、4GB、10GB、40GB,所以如果我可以在不牺牲 performance/features 的情况下减小每个数据库的大小,为什么不呢?如果我可以让一台 32GB RAM 的机器服务于 4 个客户端而不是 2 个,为什么不呢?

只需使用 INT,除非您有特定的、可衡量的问题。在这个时代,即使是最节俭的智能手机也有十亿个字节用于存储,如果你为每个字节烦恼,你只会把事情弄得一团糟。

I need the database size to be as small as possible to fit in RAM to reduce the hard-desk requests.

不,你不知道。您需要数据库易于使用并充分执行。在 SSD 支持的数据库时代,I/O 不会成为问题,除非您进行大规模操作,如果那一天到来,那么您可以进行测量并了解您遇到的具体问题。

从您的 INT 字段中去除一个字节不太可能使任何事情变得更好,因为三字节整数值不是您的 CPU 可以直接处理的东西。这些将被转换为四个字节并正确对齐,以便它们可以被理解,与读取普通的旧 32 位整数相比,这是一个混乱的过程。

记住,MySQL来自高端服务器拥有 64 兆字节 内存和 9 千兆字节[=30= 内存的时代] 硬盘被认为是巨大的。那时你确实不得不削减字节,因为你只有少数字节。

现在我们还有其他问题,例如您是否会不小心耗尽您的 24 位整数 space,例如 Slashdot did 他们的网站因 "optimizing" 您的某种原因而崩溃打算在这里做。

小心。当您有具体理由时进行优化,而不仅仅是因为您认为需要这样做。避免过早优化是开发过程中的一个持续斗争,但如果你有纪律,你就可以避免它。

索引的确切大小将取决于您拥有的行数,还取决于索引中数据的外观。

如果您在数据中每条记录削减 1 个字节,并且您有 10.000.000 条记录,那么最多只能为 table 数据节省 10MB 的磁盘空间。加个索引还要加一些,B-tree里面是空的space,但是要看实际数据有多低效

如果要保存space,请确保该字段不可空,因为即使您用数据填充所有行,每条记录都有信息,说明可空字段是否包含数据.

(我不同意 一些 的其他 Answers/Comments。我会尽力回答所有问题,并解决所有我不同意的观点。)

MEDIUMINT 是 3 个字节,比 INT.
每行节省 1 个字节 TINYINT 是 1 个字节,比 INT 每行节省 3 个字节。
在这两种情况下,除 PRIMARY KEY.

之外的任何 INDEX 每次出现都会节省另外 1 或 3 个字节

如果 RAM 中的数据+索引可能多于 space,那么缩小数据类型是明智的但是 保守点。

如果值为非负数,例如 AUTO_INCREMENT,则使用 MEDIUMINT UNSIGNED(等)。这为您提供了 16M 而不是 8M 的限制。 (是的,是的,这是一个微小的进步。)

注意 "burning" AUTO_INCREMENT ids -- INSERT IGNORE(和其他几个命令)将分配下一个 auto_inc,然后再检查它是否会被使用。

即使数据+索引超过 RAM 大小(实际上 innodb_buffer_pool_size),它也可能不会减慢磁盘速度——这取决于数据的访问模式。当心 UUID,它们非常随机。在无法缓存整个索引时使用 UUID 是致命的。 buffer_pool 是一个 缓存 。 (我见过一个 1TB 的数据集 运行 足够快,只有 32GB 的内存和一个旋转的磁盘。)

使用 ALTER TABLE 更改数据类型可能(我不确定)重建 table,从而执行相当于 OPTIMIZE TABLE.

如果 table 是用 innodb_file_per_table = OFF 创建的,并且您在执行 ALTER 之前将其设置为 ON,您将获得 table 的单独文件, 但是 ibdata1 不会缩小(相反它会有更多的空闲 space)。

3 字节数字的对齐 -- 不是问题。 2 的幂与此处 无关 。 MySQL 假设 所有 列的边界不佳且大小不佳。 所有 数字都转换为通用格式(64 位数字)以供操作。此转换占总时间的 无关紧要 部分——获取行(即使已缓存)是成本最高的部分。

当 I/O-bound 时,缩小数据类型会导致每个块有更多行,从而导致更少的磁盘命中(UUID 情况除外)。当 I/O-bound 时,占用磁盘是最大的性能成本。

"NULLS take no space" -- https://dev.mysql.com/doc/internals/en/innodb-field-contents.html 。因此,再次减少 I/O。但是,请注意,如果这导致对 SELECT 中的 NULL 进行额外检查,则可能会导致 table 扫描而不是使用索引。达到 1000 万行比只达到几行要糟糕得多。

至于 32GB 可以容纳多少个客户端 -- 也许是 6 个或更多。请记住,buffer_pool 是一个缓存;数据和索引是逐块缓存的。 (一个 InnoDB 块是 16KB。)

还有一件事...在 投入生产之前缩小数据类型要容易得多。所以,现在就做你能安全做的事吧。