【问题标题】:Why is the AVG row length 4 times as large as expected?为什么 AVG 行长度是预期的 4 倍?
【发布时间】:2021-02-01 14:38:53
【问题描述】:

我有这张桌子:

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 字节。

主元组键的 B-tree 使用的存储量是数据本身的 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 仍然很大。所以我不知道这有什么意义,但我想 10 年前情况可能有所不同。

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

【问题讨论】:

  • 请注意,INT 声明后括号中的数字几乎没有意义
  • @Strawberry 它的显示宽度,对大小没有影响,对吧?
  • 它(几乎)对任何东西都没有影响
  • @Strawberry 好的,很高兴知道 :)
  • @scaisEdge 是的,但我没有字符集字段,只有整数,所以没关系,对吧?

标签: mysql sql innodb


【解决方案1】:

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

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

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

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

  • 每个块的开销——每个 16KB 块的一些字节数

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

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

  • 随着表格从适合一个块中增长,布局算法发生变化,开销百分比暂时达到峰值。

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

  • 如果您没有可提升为 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 有问题——它只提供大约 2 倍的压缩,与典型的 3 倍文本压缩不同。由于需要同时在 buffer_pool 中保存压缩和未压缩的数据(至少对于某些块),因此需要一些 RAM。

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

【讨论】:

    猜你喜欢
    • 2012-07-16
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多