我通过为列选择正确的数据类型来学习如何优化我的数据库,如果我选择MEDIUMINT
(3字节)而不是{我想知道我将保存多少大小{1}}(4字节)
AFAIK - 如果我错了,请更正我 - 我需要尽可能小的数据库大小以适应RAM以减少硬桌请求。数据库的大小由表大小+索引大小
组成假设我有一个INT
列,其上有10&000; 000' 000行和B-Tree索引,如果我更改了数据类型,我将保存多少MB从INT
到INT
的
注意:我知道MySQL不会减少磁盘上的实际大小,除非我OPTIMIZE TABLE
编辑:我的情况是,我将很快完成我的第一个认真的系统 - 这是我计划在阿拉伯地区市场销售的ERP系统 - 。计划1,2,3,4个数据库应该分别约为2GB,4GB,10GB,40GB,所以如果我可以在不牺牲性能/功能的情况下减小每个数据库的大小,为什么不呢?如果我能让一台32GB的RAM机器服务4个客户而不是2个,为什么不呢?答案 0 :(得分:4)
Just use INT
unless you have a specific, measurable problem. You're only going to make a mess of things if you fret over every single byte in an era where even the most thrifty of smart phones has a billion of them for memory alone.
I need the database size to be as small as possible to fit in RAM to reduce the hard-desk requests.
No you don't. You need the database to be easy to work with and perform adequately. In an era of SSD-backed databases, I/O will not be a problem until you're operating at large scale, and when and if that day comes then you can take measurements and understand the specific problems you're having.
Shaving a single byte off your INT
field is unlikely to make anything better since three byte integer values are not something your CPU can directly deal with. These will be converted to four bytes and aligned properly so they can be understood, a process that's messy compared to reading a plain old 32-bit integer.
Remember, MySQL comes from an era where a high-end server had 64 megabytes of memory and a 9 gigabyte hard disk was considered huge. Back then you did have to shave bytes off because you only had a handful of them.
Now we have other concerns, like will you accidentally exhaust your 24-bit integer space like Slashdot did,因为您打算在此处进行“优化”。
小心点。当你有具体的理由时,优化,而不仅仅是因为你认为你需要。避免过早优化是一个持续的发展斗争,但如果你受到纪律处分,你可以避免它。
答案 1 :(得分:1)
索引的确切大小取决于您拥有的行数,还取决于索引中数据的外观。
如果您在数据中每个记录削减1个字节,并且您有10.000.000个记录,那么只能在磁盘上为表数据保存最多10个字节。添加一个索引会增加更多,而B树中有空的空间,但它取决于实际数据的低效率。
如果要节省空间,请确保该字段不可为空,因为即使用数据填充所有行,每条记录都有信息,说明可空字段是否包含数据。
答案 2 :(得分:1)
(我不同意其他答案/评论的一些。我会尝试回答所有问题,并解决我不同意的所有问题。)
MEDIUMINT
为3个字节,每行节省1个字节INT
TINYINT
为1个字节,每行节省3个字节INT
在这两种情况下,除INDEX
之外的任何PRIMARY KEY
中每次出现另外保存1或3个字节。
如果您的RAM中的数据+索引可能比空间多,那么 明智地缩小数据类型,但是保守的。
如果值为非负值,请使用MEDIUMINT UNSIGNED
(等),例如AUTO_INCREMENT
。这样可以限制16M而不是8M。 (是的,是的,这是一个很小的改进。)
小心“刻录”AUTO_INCREMENT
ids - INSERT IGNORE
(以及其他几个命令)将在检查是否将使用之前分配下一个auto_inc。
即使数据+索引超过RAM大小(实际上是innodb_buffer_pool_size
),它也可能不会降低到磁盘速度 - 它取决于数据的访问模式。谨防UUID,它们非常随机。当你无法缓存整个索引时使用UUID是致命的。 buffer_pool是缓存。 (我已经看到1TB数据集运行得足够快,只有32GB的RAM和旋转磁盘。)
使用ALTER TABLE
更改数据类型可能(我不确定)重建表,从而执行等效的OPTIMIZE TABLE
。
如果表格是使用innodb_file_per_table = OFF
创建的,并且您在执行ON
之前将其设为ALTER
,那么您将获得该表的单独文件,但 { {1}}不会缩小(相反,它会有更多的可用空间)。
3字节数字的对齐 - 不是问题。 2的权力不相关。 MySQL假设所有列的边界都很差,而且大小也很差。 所有号码都转换为通用格式(64位数字)以便进行操作。此转换是总时间的无关紧要部分 - 获取行(即使缓存)是最昂贵的部分。
当受I / O限制时,缩小的数据类型会导致每个块有更多行,这会导致更少的磁盘命中(UUID情况除外)。当I / O绑定时,击中磁盘是最大的性能成本。
“NULLS不占空间” - https://dev.mysql.com/doc/internals/en/innodb-field-contents.html。因此,再次减少I / O.但是,请注意,如果这导致ibdata1
中NULL
的额外检查,则可能导致表扫描而不是使用索引。击中10M行比仅仅打几个行要糟糕得多。
至于有多少客户可以容纳32GB - 可能是6或更多。记住,buffer_pool是一个缓存;数据和索引是逐块缓存的。 (InnoDB块为16KB。)
还有一件事......在投入生产之前缩小数据类型要容易得多。所以,做你现在可以安全做的事。