mysql - InnoDB 行大小在表增长时呈指数变化?

标签 mysql primary-key innodb mysql-5.6

我有一个包含三列(int、mediumint、int)的巨大 InnoDB 表。 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;

MySQL版本为5.6.16

目前我每秒多行插入超过 150 行。没有删除,也没有更新。 没有明显的回滚或其他事务中止,这会导致空间使用浪费。

MySQL 显示该表的计算大小为 75.7GB。

.ibd size on disc: 136,679,784,448 byte (127.29 GiB)

Counted rows: 2,901,937,966 (47.10 byte per row)

2 天后,MySQL 还显示该表的计算大小为 75.7 GB。

.ibd size on disc: 144,263,086,080 byte (135.35 GiB)

Counted rows: 2,921,284,863 (49.38 byte per row)

为表运行 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

这是我的问题:

  • 为什么磁盘使用量的增长与行数不成比例?
  • 为什么 Avg_row_lengthData_length 完全是错误的?

希望有人能帮助我,光盘使用量不会再像这样增长了。我没有注意到,因为 table 较小。

最佳答案

我假设您的表还没有有机地增长到现在的 29 亿行,并且您最近加载了这些数据或者导致表被重新组织(使用 ALTER TABLEOPTIMIZE 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

InnoDB 绝不会实际填充页面超过大约 ~15/16 满(通常绝不会少于 1/2 满)。由于各个地方的所有额外开销,一条记录的满载成本约为索引的叶页中每行最少 32 字节和最多 60 字节。

当您通过导入或通过 ALTER TABLEOPTIMIZE TABLE 批量加载数据时,数据通常会按顺序加载(并创建索引) PRIMARY KEY,它允许 InnoDB 非常有效地打包磁盘上的数据。如果您随后继续以随机(或实际上随机)顺序向表中写入数据,则有效打包的索引结构必须扩展以接受新数据,这在 B+Tree 术语中意味着将页面分成两半。如果你有一个理想打包的 16 KiB 页面,其中记录平均消耗 ~32 字节,并且它被分成两半以插入一行,你现在有两个半空页面(~16 KiB 浪费)并且新行有“成本”16 KiB。

当然这不是真的。随着时间的推移,索引树会在 1/2 满和 15/16 满之间的某处稳定下来——它不会永远拆分页面,因为必须发生在同一页面中的下一次插入会发现已经有足够的空间存在做插入。

不过,如果您最初将数据批量加载(并因此有效地打包)到表中,然后切换到有机增长,这可能会有点令人不安。最初,表格似乎正在以疯狂的速度增长,但如果您随着时间的推移跟踪增长率,它应该会放缓。

您可以在我的博文中阅读更多关于 InnoDB 索引和记录布局的信息:The physical structure of records in InnoDB , The physical structure of InnoDB index pages , 和 B+Tree index structures in InnoDB .

关于mysql - InnoDB 行大小在表增长时呈指数变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22037778/

相关文章:

android - 不使用get方法将数据从android应用程序发送到mysql

Mysql,无法创建表

php - 如果我的主键不自动递增,如何使用 PHP 获取最后插入的 ID

php - 在 MySQL 中使用 NoSQL

mysql - 确保 cron 作业不会重复执行相同的作业

mysql - 搜索并删除 mySQL 表中的孤立项

mysql - MySQL InnoDB 与 MyISAM 中的复杂查询性能

php - MySQL 查询增强性能取决于日期

mysql 创建过程语法问题第 1 行

java - 为什么我必须输入 ID (PK) - 自动生成 ID 的问题