Ste*_*fan 5 mysql innodb primary-key mysql-5.6
我有一个巨大的InnoDB表,有三列(int,mediumint,int).在innodb_file_per_table设置上,并且只有一个PRIMARY KEY头两列的
表模式是:
CREATE TABLE `big_table` (
`user_id` int(10) unsigned NOT NULL,
`another_id` mediumint(8) unsigned NOT NULL,
`timestamp` int(10) unsigned NOT NULL,
PRIMARY KEY (`user_id`,`another_id `)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Run Code Online (Sandbox Code Playgroud)
MySQL版本是5.6.16
目前我每秒多插入超过150行.没有删除,也没有更新.没有重大的回滚或其他事务中止,这将导致浪费的空间使用.
MySQL在该表上显示计算出的大小为75,7GB.
光盘上的.ibd大小:136,679,784,448字节(127.29 GiB)
计数行:2,901,937,966(每行47.10字节)
2天后,MySQL在该表上显示的计算大小为75.7 GB.
光盘上的.ibd大小:144,263,086,080字节(135.35 GiB)
计数行:2,921,284,863(每行49.38字节)
跑步SHOW TABLE STATUS表显示:
Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Collation
InnoDB | 10 | Compact | 2645215723 | 30 | 81287708672 | 0 | 0 | 6291456 | utf8_unicode_ci
Run Code Online (Sandbox Code Playgroud)
这是我的问题:
Avg_row_length和Data_length 完全错了吗?希望有人可以帮助我,光盘使用不再像这样增长.我没有注意到,因为桌子较小.
我假设你的表没有有机地增长到现在的~29亿行,并且你最近加载了这些数据或导致表重组(使用ALTER TABLE或者OPTIMIZE TABLE例如).所以它开始在磁盘上非常好.
根据您的表模式(幸运的是非常简单和直接),每行(记录)的布局如下:
(Header) 5 bytes
`user_id` 4 bytes
`another_id` 3 bytes
(Transaction ID) 6 bytes
(Rollback Pointer) 7 bytes
`timestamp` 4 bytes
=============================
Total 29 bytes
Run Code Online (Sandbox Code Playgroud)
InnoDB永远不会实际填充页面超过约15/16满(通常不会少于1/2满).由于各种位置的所有额外开销,记录的完整加载成本在索引的叶页中最小约32字节和每行最多60字节.
当您通过导入或通过ALTER TABLE或批量加载数据时OPTIMIZE TABLE,通常会按顺序加载数据(并创建索引)PRIMARY KEY,这样InnoDB可以非常有效地将数据打包到磁盘上.如果随后继续以随机(或有效随机)顺序将数据写入表中,则必须扩展高效打包的索引结构以接受新数据,这在B + Tree术语中意味着将页面拆分为一半.如果你有一个理想的16 KiB页面,其中记录平均消耗约32个字节,并且它被分成两半以插入一行,你现在有两个半空页面(约16 KiB浪费)并且新行有"成本"16 KiB.
当然,这不是真的.随着时间的推移,索引树会在页面介于1/2满和15/16之间的情况下稳定下来 - 它不会永久地分割页面,因为必须发生在同一页面中的下一个插入将发现已经有足够的空间存在进行插入.
如果您最初将数据批量加载(并因此有效地打包)到表中然后切换到有机增长它,这可能有点令人不安.最初似乎桌子正以疯狂的速度增长,但如果你跟踪增长率,它应该放慢速度.
你可以在我的博客文章阅读更多关于InnoDB的索引和记录布局:InnoDB的记录的物理结构,InnoDB的索引页的物理结构,而InnoDB的B +树索引结构.