10.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换
本节介绍在utf8mb3
和utf8mb4
字符集之间转换字符数据时可能遇到的问题。
Note
该讨论主要集中在utf8mb3
和utf8mb4
之间的转换,但是类似的原理适用于ucs2
字符集和诸如utf16
或utf32
之类的字符集之间的转换。
utf8mb3
和utf8mb4
字符集的区别如下:
-
utf8mb3
仅支持基本多语言平面(BMP)中的字符。utf8mb4
还支持 BMP 之外的补充字符。 -
utf8mb3
每个字符最多使用三个字节。utf8mb4
每个字符最多使用四个字节。
Note
该讨论引用的是utf8mb3
和utf8mb4
字符集名称,以明确地引用 3 字节和 4 字节 UTF-8 字符集数据。exception 是在 table 定义中使用utf8
,因为 MySQL 会将此类定义中指定的utf8mb3
的实例转换为utf8
,这是utf8mb3
的别名。
从utf8mb3
转换为utf8mb4
的一个优点是,这使应用程序可以使用补充字符。一种折衷是这可能增加数据存储空间需求。
就 table 内容而言,从utf8mb3
转换为utf8mb4
不会出现问题:
-
对于 BMP 字符,
utf8mb4
和utf8mb3
具有相同的存储 Feature:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf8mb4
需要四个字节来存储它,而utf8mb3
根本不能存储该字符。将utf8mb3
列转换为utf8mb4
时,您无需担心转换补充字符,因为将没有补充字符。
就 table 结构而言,这些是潜在的主要不兼容性:
-
对于可变长度字符数据类型(VARCHAR和TEXT类型),
utf8mb4
列的字符允许的最大长度小于utf8mb3
列的字符的最大允许长度。 -
对于所有字符数据类型(CHAR,VARCHAR和TEXT类型),
utf8mb4
列的索引最大字符数少于utf8mb3
列的索引数。
因此,要将 table 从utf8mb3
转换为utf8mb4
,可能需要更改某些列或索引定义。
可以使用ALTER TABLE将 table 从utf8mb3
转换为utf8mb4
。假设一个 table 具有以下定义:
CREATE TABLE t1 (
col1 CHAR(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
col2 CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) CHARACTER SET utf8;
以下语句将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
时,要注意的是,列或索引键的最大长度以* bytes *不变。因此,就字符而言,它更小,因为一个字符的最大长度是四个字节而不是三个字节。对于CHAR,VARCHAR和TEXT数据类型,在转换 MySQLtable 时请注意以下问题:
-
检查
utf8mb3
列的所有定义,并确保它们不会超过存储引擎的最大长度。 -
检查
utf8mb3
列上的所有索引,并确保它们不会超过存储引擎的最大长度。有时,由于存储引擎的增强,最大值可能会更改。
如果满足上述条件,则必须减少定义的列或索引的长度,或者 continue 使用utf8mb3
而不是utf8mb4
。
以下是一些可能需要进行结构更改的示例:
- TINYTEXT列最多可容纳 255 个字节,因此最多可容纳 85 个 3 字节或 63 个 4 字节字符。假设您有一个使用
utf8mb3
的TINYTEXT列,但必须包含 63 个以上的字符。除非将数据类型更改为更长的类型,例如TEXT,否则不能将其转换为utf8mb4
。
同样,如果要将VARCHAR较长的列从utf8mb3
转换为utf8mb4
,则可能需要将其更改为较长的TEXT类型之一。
- 对于使用
COMPACT
或REDUNDANT
行格式的 table,InnoDB
的最大索引长度为 767 字节,因此对于utf8mb3
或utf8mb4
列,您最多可以分别索引 255 个或 191 个字符。如果当前有utf8mb3
列的索引长于 191 个字符,则必须索引较少的字符。
在使用COMPACT
或REDUNDANT
行格式的InnoDB
table 中,这些列和索引定义是合法的:
col1 VARCHAR(500) CHARACTER SET utf8, INDEX (col1(255))
要改为使用utf8mb4
,索引必须较小:
col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))
Note
对于使用COMPRESSED
或DYNAMIC
行格式的InnoDB
table,您可以启用innodb_large_prefix选项以允许索引键前缀长于 767 字节(最多 3072 字节)。创建此类 table 还需要选项值innodb_file_format=barracuda和innodb_file_per_table=true。)在这种情况下,启用innodb_large_prefix选项可使您分别为utf8mb3
或utf8mb4
列索引最多 1024 个或 768 个字符。有关相关信息,请参见第 14.23 节“ InnoDB 限制”。
仅当列或索引很长时,才有可能需要进行上述更改。否则,您应该能够使用ALTER TABLE如前所述将 table 从utf8mb3
转换为utf8mb4
而不出现问题。
以下各项总结了其他潜在的不兼容性:
-
SET NAMES 'utf8mb4'
导致将 4 字节字符集用于连接字符集。只要服务器没有发送 4 字节字符,就不会有问题。否则,期望每个字符最多接收三个字节的应用程序可能会出现问题。相反,希望发送 4 字节字符的应用程序必须确保服务器能够理解它们。 -
对于复制,如果要在主服务器上使用支持补充字符的字符集,则所有从服务器也必须理解它们。
另外,请记住以下一般原则:如果 table 在主服务器和从服务器上具有不同的定义,则可能导致意外的结果。例如,最大索引键长度的差异使得在主服务器上使用utf8mb3
并在从服务器上使用utf8mb4
很有风险。
如果您已转换为utf8mb4
,utf16
,utf16le
或utf32
,然后决定转换回utf8mb3
或ucs2
(例如,降级到旧版本的 MySQL),则适用以下注意事项:
-
utf8mb3
和ucs2
数据应该没有问题。 -
服务器必须具有足够的最新性,以识别引用所要转换的字符集的定义。
-
对于引用
utf8mb4
字符集的对象定义,您可以在降级之前用mysqldump转储它们,编辑转储文件以将utf8mb4
的实例更改为utf8
,然后在没有旧版本的服务器中重新加载文件,只要没有 4-数据中的字节字符。较旧的服务器将在转储文件对象定义中看到utf8
,并创建使用(3 字节)utf8
字符集的新对象。