5

我有一个包含三列(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 磁盘大小: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

这是我的问题:

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

希望有人可以帮助我,磁盘使用量不会再像这样增长了。我没有注意到,因为桌子更小。

4

1 回答 1

7

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

InnoDB 实际上永远不会将页面填充到大约 15/16 左右(通常不会少于 1/2)。由于各个地方的所有额外开销,记录的满载成本大约是索引叶页中每行最小 32 字节和最大 60 字节。

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

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

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

您可以在我的博客文章中阅读更多关于 InnoDB 索引和记录布局的信息: InnoDB中记录的物理结构、InnoDB 索引页的物理结构和 InnoDB中的B+Tree 索引结构

于 2014-02-26T19:00:00.273 回答