文档首页
MySQL 8.4 参考手册
相关文档 下载本手册

MySQL 8.4 参考手册  /  ...  /  在 3 字节和 4 字节 Unicode 字符集之间转换

12.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换

本节介绍在 utf8mb3 和 utf8mb4 字符集之间转换字符数据时可能遇到的问题。

注意

本讨论主要集中在 utf8mb3 和 utf8mb4 之间的转换,但类似的原则也适用于在 ucs2 字符集与 utf16 或 utf32 等字符集之间进行转换。

utf8mb3 和 utf8mb4 字符集的区别如下

  • utf8mb3 只支持基本多语言平面 (BMP) 中的字符。 utf8mb4 另外支持 BMP 之外的补充字符。

  • utf8mb3 每个字符最多使用三个字节。 utf8mb4 每个字符最多使用四个字节。

注意

本讨论使用 utf8mb3 和 utf8mb4 字符集名称来明确表示 3 字节和 4 字节 UTF-8 字符集数据。

从 utf8mb3 转换为 utf8mb4 的一个优点是,这使应用程序能够使用补充字符。一个折衷方案是,这可能会增加数据存储空间需求。

就表内容而言,从 utf8mb3 转换为 utf8mb4 没有任何问题

  • 对于 BMP 字符,utf8mb4 和 utf8mb3 具有相同的存储特性:相同的代码值、相同的编码、相同的长度。

  • 对于补充字符,utf8mb4 需要四个字节来存储它,而 utf8mb3 根本无法存储该字符。在将 utf8mb3 列转换为 utf8mb4 时,您无需担心转换补充字符,因为没有补充字符。

就表结构而言,这些是主要的潜在不兼容性

  • 对于可变长度字符数据类型(VARCHAR 和 TEXT 类型),utf8mb4 列的字符最大允许长度小于 utf8mb3 列的字符最大允许长度。

  • 对于所有字符数据类型(CHAR、VARCHAR 和 TEXT 类型),utf8mb4 列可以索引的字符最大数量小于 utf8mb3 列可以索引的字符最大数量。

因此,要将表从 utf8mb3 转换为 utf8mb4,可能需要更改某些列或索引定义。

可以使用 ALTER TABLE 将表从 utf8mb3 转换为 utf8mb4。假设一个表有以下定义

CREATE TABLE t1 (
  col1 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NOT NULL,
  col2 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL
) CHARACTER SET utf8mb3;

以下语句将 t1 转换为使用 utf8mb4

ALTER TABLE t1
  DEFAULT CHARACTER SET utf8mb4,
  MODIFY col1 CHAR(10)
    CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  MODIFY col2 CHAR(10)
    CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;

从 utf8mb3 转换为 utf8mb4 时,需要注意的是,列或索引键的最大长度在 字节 方面没有改变。因此,在 字符 方面它更小,因为字符的最大长度是四个字节,而不是三个字节。对于 CHAR、VARCHAR 和 TEXT 数据类型,在转换 MySQL 表时要注意以下问题

  • 检查所有 utf8mb3 列的定义,确保它们不超过存储引擎的最大长度。

  • 检查所有 utf8mb3 列上的索引,确保它们不超过存储引擎的最大长度。有时最大长度会因存储引擎的增强而改变。

如果上述情况适用,则必须减少列或索引的定义长度,或者继续使用 utf8mb3 而不是 utf8mb4。

以下是一些可能需要进行结构性更改的示例

  • TINYTEXT 列最多可以容纳 255 个字节,因此它最多可以容纳 85 个 3 字节或 63 个 4 字节字符。假设您有一个使用 utf8mb3 的 TINYTEXT 列,但必须能够包含超过 63 个字符。除非您还将数据类型更改为更长的类型(如 TEXT),否则您无法将其转换为 utf8mb4。

    类似地,如果您要将非常长的 VARCHAR 列从 utf8mb3 转换为 utf8mb4,则可能需要将其更改为更长的 TEXT 类型之一。

  • InnoDB 对于使用 COMPACT 或 REDUNDANT 行格式的表,最大索引长度为 767 个字节,因此对于 utf8mb3 或 utf8mb4 列,您最多可以索引 255 个或 191 个字符。如果您当前有 utf8mb3 列,并且其索引长度超过 191 个字符,则必须索引更少的字符。

    在使用 COMPACT 或 REDUNDANT 行格式的 InnoDB 表中,以下列和索引定义是合法的

    col1 VARCHAR(500) CHARACTER SET utf8mb3, INDEX (col1(255))

    要使用 utf8mb4,索引必须更小

    col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))
    注意

    对于使用 COMPRESSED 或 DYNAMIC 行格式的 InnoDB 表,允许使用长度超过 767 字节(最多 3072 字节)的 索引键前缀。使用这些行格式创建的表可以为 utf8mb3 或 utf8mb4 列分别索引最多 1024 或 768 个字符。有关相关信息,请参阅 第 17.21 章,“InnoDB 限制” 和 DYNAMIC 行格式。

只有在您拥有非常长的列或索引时,才最有可能需要上述类型的更改。否则,您应该能够使用前面描述的 ALTER TABLE 将您的表从 utf8mb3 转换为 utf8mb4,而不会出现问题。

以下内容总结了其他潜在的不兼容性

  • SET NAMES 'utf8mb4' 会导致将 4 字节字符集用于连接字符集。只要服务器没有发送任何 4 字节字符,就不会出现问题。否则,期望接收每个字符最多三个字节的应用程序可能会遇到问题。相反,期望发送 4 字节字符的应用程序必须确保服务器能够理解它们。

  • 对于复制,如果要在源上使用支持补充字符的字符集,则所有副本也必须理解它们。

    此外,请记住一般原则,如果表在源和副本上具有不同的定义,这会导致意外结果。例如,最大索引键长度的差异使得在源上使用 utf8mb3 而在副本上使用 utf8mb4 具有风险。

如果您已转换为 utf8mb4、utf16、utf16le 或 utf32,然后决定转换回 utf8mb3 或 ucs2(例如,降级到旧版本的 MySQL),则以下考虑因素适用

  • utf8mb3 和 ucs2 数据不应出现任何问题。

  • 服务器必须足够新,才能识别引用您要转换的字符集的定义。

  • 对于引用 utf8mb4 字符集的对象定义,您可以在降级之前使用 mysqldump 将其转储,编辑转储文件以将 utf8mb4 的实例更改为 utf8,并在旧服务器中重新加载文件,只要数据中没有 4 字节字符即可。旧服务器在转储文件对象定义中看到 utf8,并创建使用 (3 字节) utf8 字符集的新对象。