为什么AVG行长度是预期的4倍?

问题描述

我有这张桌子:

CREATE TABLE `tree_paths` (
  `child_id` int(10) unsigned NOT NULL,`parent_id` int(10) unsigned NOT NULL,`sponsor_upline` tinyint(1) NOT NULL DEFAULT '0',`left_leg` tinyint(1) NOT NULL,`binary_level` smallint(5) unsigned NOT NULL DEFAULT '0',`sponsor_level` smallint(5) unsigned NOT NULL DEFAULT '0',PRIMARY KEY (`child_id`,`parent_id`),KEY `tree_paths_parent_id_foreign` (`parent_id`),CONSTRAINT `tree_paths_child_id_foreign` FOREIGN KEY (`child_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,CONSTRAINT `tree_paths_parent_id_foreign` FOREIGN KEY (`parent_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

int(10)消耗4字节,smallint(5) 2字节,tinyint(1) 1字节。因此,一行原始数据应为14字节。

我插入了约1600万行。由于某些原因,AVG行长度为57字节而不是14字节。

enter image description here

元组键的B树使用的存储量是数据本身的3倍是否现实?

此外,我已经读过https://stackoverflow.com/a/30318725/2311074

主键已经在DATA_LENGTH中进行了计算。 INDEX_LENGTH表示“所有二级索引的大小”。

如果是这样,那么为什么index_length为总大小的1/4?正如上面所看到的,我没有辅助键。还是来自FOREIGN键?

备注:

我发现了与我类似的问题。

一个Why is InnoDB table size much larger than expected?,但它已经有10年的历史了,我一点都不明白。该问题的答案是,隐藏的6字节列是造成此差异的原因。但是,差异不是6,而是36。并且用户未使用任何键,但Index_length仍然很大。所以我不知道这有什么意义,但是我想十年前情况可能有所不同。

我找到的另一个答案是在Average row length higher than possible。这个答案的重点是InnoDb分配了比所需更多的空间。但是,当我检查show table status时,发现还有7.3 MB的可用空间。所以看来我可以驳斥这一点。

解决方法

平均行大小偏高的原因很多。

  • 是一个近似值。 (我发现它通常高2到3倍。)在一种极端情况下(表中的一行),每行将占用16384个字节。那是一个InnoDB块。表中的行数是估计的。用于行的磁盘空间是准确的,但请参见下面的开销。平均行大小是这两者的商。

  • 每列的开销-1或2个字节

  • 每行的开销-20-30字节-用于处理事务,查找块中的行等

  • 每个块的开销-每个16KB块的字节数

  • 在BTree中颠簸的开销-最小值约为一个块的1/16,最大值约为该块的一半,经过大量删除和/或随机插入后,平均值约为30%。

  • 用于预分配大块磁盘空间(1MB?8MB?)的开销

  • 随着一张桌子的尺寸从一个块开始增长,布局算法发生变化,间接费用的百分比暂时上升。

  • 已删除的行不会将其空间返回给操作系统,因此文件大小保持不变,从而增加了 apparent 行的大小。

  • 如果您没有可升级为PK的显式PRIMARY KEYUNIQUE密钥,则PK将有一个不可访问的6字节字段(每行)。

  • TEXT / BLOB甚至VARCHAR都被“记录外”存储。这使计算复杂得多。它取决于您使用的是4 ROW_FORMATs中的哪一个。在某些情况下,每个这样的单元都有一个20字节的“指针”。

  • FOREIGN KEY约束不会增加所需的空间,只是它们 可能会强制创建索引。

  • 除了INDEXes之外,
  • PRIMARY KEY都没有包含在avg_row_length中。

  • PRIMARY KEY 通常通常在 data BTree中的开销很小。一个简单的经验法则是1%的开销(在列本身之上)。这个开销是BTree的非叶子节点。

  • InnoDB事务繁忙时,所有已修改的行都保留在“历史记录列表”中。这会导致更多开销。

  • (不完全相关)。 InnoDB的COMPRESSED存在问题-与一般的3x文本压缩不同,它仅提供大约2x的压缩。由于需要同时将buffer_pool中的压缩数据和未压缩数据同时存储(至少用于某些块),因此需要一些RAM。

SHOW TABLE STATUS并从information_schema.TABLES中获取相同的数据。有一些方法可以使数据和每个表对B + Tree的深度有一些了解。