【问题标题】:Why table's index storage size is bigger after change charset from utf8mb4 to utf8?为什么将字符集从 utf8mb4 更改为 utf8 后表的索引存储大小更大?
【发布时间】:2019-10-23 03:09:28
【问题描述】:

执行:alter table device_msg convert to character set 'utf8' COLLATE 'utf8_unicode_ci';"

正如我所料,表数据大小变小了。

但与此同时,表索引大小变大了?

发生了什么以及为什么?

ps:表数据大小和索引大小由information_schema.TABLES计算


数据库引擎:InnoDB

前表:

CREATE TABLE `device_msg` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `sn` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
  `time` datetime(3) NOT NULL,
  `msg` json NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `device_UNIQUE` (`sn`,`time`)
) ENGINE=InnoDB AUTO_INCREMENT=62077733 DEFAULT CHARSET=utf8mb4;

之后的表格:

CREATE TABLE `device_msg` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `sn` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
  `time` datetime(3) NOT NULL,
  `msg` json NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `device_UNIQUE` (`sn`,`time`)
) ENGINE=InnoDB AUTO_INCREMENT=62077733 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


之前:

totalSize: 2.14 GB
indexSize: 282.98 MB
dataSize: 1.86 GB
avg_row_len:  297B

之后

totalSize: 1.93 GB
indexSize: 413.97 MB
dataSize: 1.52 GB
avg_row_len:  260B

如果information_schema.TABLES的数据不准确,

如何做到正确?

【问题讨论】:

    标签: mysql performance character-encoding


    【解决方案1】:
    • utf8mb4 占用的空间,然后是 utf8(假设事先没有 4 字节字符)是相同的,不管你显示的数字是多少

      李>
    • 这个ALTER 需要重建表和索引。

    • InnoDB 在 BTree 中构建数据和每个二级索引。

    • 根据将元素插入 BTree 的顺序,会发生更多或更少的“块拆分”。

    所以,你不能说到底是字符集改变还是重建导致索引变大而数据变小。

    我说这是不是字符集更改。

    【讨论】:

      【解决方案2】:

      在我看来

      正如我在 MySQL 上阅读的有关限制的文档。

      https://dev.mysql.com/doc/refman/5.6/en/innodb-restrictions.html

      默认情况下,索引键前缀长度限制为767字节

      如果索引列超过这个大小,它将被截断。 我假设您的索引列值有 255 个字符。

      对于 utf8mb4,1 个字符 = 4 个字节,限制为 191 个字符左右。 因此 191 个字符将添加到索引中,其他 (255-191=64) 个字符将从索引中截断。

      当您将编码更改为 utf8(当时 1 个字符 = 3 个字节)时,索引限制将变为大约 255 个字符。 这意味着您的列值,所有 255 个字符,将被添加到索引中而不被截断。

      添加到索引的字符从 191 个字符增加到 255 个字符,因此索引大小也增加了。

      【讨论】:

      • 索引列值的长度小于48 主键是整数唯一键device_UNIQUE$sn_$timestamp (24+1+13)
      • 你是用这个查询得到index_length并和上面的数字比较的吗?从 [db_name] 显示表状态
      • 我只是按照你说的运行show table status。输出结果是 `Index_length = 296730624` , ~ 282.98MB 然后我回去查看 information_schema.TABLES。然后我发现数据更改为与显示状态的结果相同。 ???在阅读您的答案之前,我曾经运行过optimize table。 .哪个查询会影响 information_schema.TABLES
      • 是的,我也对自己的数据进行了测试,似乎索引大小没有改变。我不确定是否有任何情况下 information_schema.TABLES 在更新数据时缓慢?我也会研究更多。
      • 255 和 767 与问题无关。超出大小将不会截断(发生其他事情)。 1 个 utf8 字符 最多 3 个字节。
      猜你喜欢
      • 1970-01-01
      • 2016-11-18
      • 1970-01-01
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多