Mysql表大小与我的计算不符

时间:2014-04-24 09:21:30

标签: mysql storage innodb

我在MySQL中有以下表格:

CREATE TABLE `ParaTable` (
    `id_1` INT(10) UNSIGNED NULL DEFAULT '0',
    `id_2` INT(10) UNSIGNED NULL DEFAULT '0',
    `id_3` TINYINT(3) UNSIGNED NULL DEFAULT '0',
    `id_4` TINYINT(3) UNSIGNED NULL DEFAULT '0',
    `id_5` INT(10) UNSIGNED NULL DEFAULT '0',
    `date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX `id_1` (`id_1`),
    INDEX `id_2` (`id_2`),
    INDEX `date` (`date`),
    INDEX `id_3` (`id_3`),
    INDEX `id_4` (`id_4`),
    INDEX `id_5` (`id_5`),
    INDEX `multi_index` (`id_1`, `id_3`, `id_4`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

总共有大约70,000,000个条目,即使这些列可以为空,任何条目中的条目都没有NULL(表格结构不是这里的问题)。

如果我查看information_schema,我可以看到索引长度为10272899072,数据长度为3201302528。

这总计12,850MB,或大约12.54GB。

这个数字是如何计算的?

SHOW TABLE STATUS ... LIKE ParaTable的输出显示:

Rows: 68129609
Avg_row_length: 47
Data_length: 3201302528       (=3053MB)
Index_length: 10272899072     (=9797MB)

我阅读了有关数据存储空间in the MySQL manual的内容,并进行了以下粗略计算:

(INT + INT + TINYINT + TINYINT + INT +时间戳)

4 + 4 + 1 + 1 + 4 + 4 =每行18个字节(+ 6位,因为每列可以为空,我假设我可以将这6位计算为另一个字节并且是安全的,请参阅{{ 3}})=每行19个字节。

(即使每个6位在磁盘上占用1个字节,我猜不太可能,每行24个字节。)

18 bytes * 70,000,000 rows = 1260000000B = ~1200MB
(19 bytes * 70,000,000 rows = 1330000000B = ~1270MB)
(24 bytes * 70,000,000 rows = 1680000000B = ~1600MB)

我不知道mysql占用索引的空间有多大(我只能从SHOW TABLES获取值,但它是如何计算的?)。这是计算所需总大小时缺少的一个环节。但即使索引与它没有任何关系,仅Data_length似乎太高了。

为什么Avg_row_length 47而不是我计算的18-24个字节?我在这里缺少什么?

1 个答案:

答案 0 :(得分:2)

您错过了计算InnoDB存储这些行的所有开销。你应该:

  4 (INT)
+ 4 (INT)
+ 1 (TINYINT)
+ 1 (TINYINT)
+ 4 (INT)
+ 4 (TIMESTAMP)
+ 1 (Null bitmap, rounded up to whole bytes)
+ 5 (Row header)
+ 6 (ROW_ID: Implicit cluster key, because you are missing a PRIMARY KEY)
+ 6 (TRX_ID: Transaction ID)
+ 7 (ROLL_PTR: Rollback/undo pointer)
= 43 bytes per row

然后,您还需要考虑页面填充率(页面不是按设计填充到100%),这绝对最小值增加了~7%:

  43
* 1 / (15/16)
= 45.86 bytes per row

此外,您将在已分配但未使用的空间中获得开销。

实际上,每行大约47个字节并不坏。最糟糕的情况是开销消耗~50%,导致表每行占用~86个字节。

对于每个辅助密钥,请注意它们的空间消耗情况如下(以id_1为例):

  4 (INT)
+ 1 (Null bitmap, rounded up to whole bytes)
+ 5 (Row header)
+ 6 (ROW_ID: Implicit cluster key)
= 16 bytes per row
* 1 / (15/16)
= 17.06 bytes per row

阅读以下关于InnoDB数据结构的帖子可能会有用,以了解更多信息: