MySQL的char和varchar字符集及存储大小

13

想知道这两种数据类型实际占用的存储空间有多少,因为MySQL文档对此有些不清楚。

CHAR(M) M × w字节,其中0 ≤ M ≤ 255,w是字符集中最大长度字符所需的字节数

VARCHAR(M),VARBINARY(M) 如果列值需要0-255字节,则为L + 1字节,如果值可能需要超过255字节,则为L + 2字节

这似乎暗示着,假设给定一个utf8编码的数据库,每个字符的CHAR始终占用32位,而VARCHAR将根据存储的实际字节长度在8到32之间占用不等大小的位数。这正确吗?还是说VARCHAR意味着8位字符宽度,并且存储多个字节的UTF8字符实际上会从VARCHAR中消耗多个'字符'?或者VARCHAR也总是以每个字符32位的方式进行存储?有太多的可能性了。

我以前从来没有像现在这样担心过这个问题,但我开始到达内存临时表大小限制,我不一定想要增加MySQL的可用池(第二次)。

1个回答

15

CHARVARCHAR都计算字符数。它们都根据字符编码和长度计算可能需要的最大存储空间。对于ASCII码,每个字符占用1个字节。对于UTF-8编码,每个字符占用3个字节(不是4个字节,因为MySQL的Unicode支持有限,它不支持在UTF-8中需要4个字节的任何Unicode字符)。到目前为止,CHARVARCHAR是相同的。

现在,CHAR直接预留了这个存储空间。

VARCHAR则分配了1或2个字节,取决于这个最大存储空间是否小于256个字节。实际占用条目的空间量是这些1或2个字节加上字符串实际占用的空间量。

有趣的是,这使得85成为UTF-8 VARCHAR的“魔法数字”:

  • VARCHAR(85)使用1个字节的长度,因为85个UTF-8字符的最大可能长度是3×85=255。
  • VARCHAR(86)使用2个字节的长度,因为86个UTF-8字符的最大可能长度是3×86=258。

1
此外,MySQL的utf8存储不仅受到了限制,而且它也不是标准的UTF-8。使用utf8编码的字符串存储需要大约两倍于常规UTF-8编码字符串的存储空间,使其更加低效。 - deceze
@deceze 我不知道那个。你有关于那个的详细信息或参考资料吗? - Celada
我希望我能做到,但是文档上并没有提供太多信息。最近这里有一个关于转储数据库的问题,其中数据以二进制形式转储,这就很明显了。 - deceze
谢谢大家,这为我们提供了一些很好的启示。关于UTF8下的85个字符长度很有趣 - 所以基本上,在utf8编码的数据库中通常的varchar(255)根本不会节省任何空间? - pospi
3
看起来比那更加复杂。例如,InnoDB有两种不同的行格式 (COMPACTREDUNDANT),因此一行占用的空间取决于哪种正在使用。当只有 MyISAM 这个存储引擎通常被使用时,情况已不再像以前那么简单了。无论如何,1 个字节的区别是微不足道的。你更可能关心的是 InnoDB 中键的最大长度,它为 768 个字节。因此,UTF-8 VARCHAR(256) 不能成为键的一部分。UTF-8 VARCHAR(255) 字段 可以 成为键。 - Celada
1
啊,情节变得更加复杂了..好的,知道了。我还注意到在MySQL的后续版本中有一个“utf8mb4”字符集可用,这是对他们之前使用的受限制的utf8字符集的修复。 - pospi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接