MySQL 字符集:Unicode 支持
关于
Unicode 标准包括来自基本多语言平面(BMP)的字符和位于 BMP 之外的补充字符。【BMP,见“关于:基本多语言平面(BMP)”】
BMP 字符具有以下特征:
- 它们的代码点值在 0 到 65535 之间(或 U+0000 和 U+FFFF)。
- 它们可以使用 8 位,16 位或 24 位(1 到 3 个字节)以可变长度编码进行编码。
- 它们可以使用 16 位(2 字节)以固定长度编码进行编码。
- 它们足以应付主要语言中的几乎所有字符。
补充字符位于 BMP 之外:
- 它们的代码点值在 U+10000 和 U+10FFFF 之间)。
- Unicode 对补充字符的支持要求字符集的范围超出 BMP 字符,因此比 BMP 字符占用更多的空间(每个字符最多 4 个字节)。
根据 RFC 3629 实现了用于对 Unicode 数据进行编码的 UTF-8(具有 8 位单位的 Unicode 转换格式)方法,该方法描述了从一到四个字节的编码序列。 UTF-8 的思想是使用不同长度的字节序列对各种 Unicode 字符进行编码:
- 基本的拉丁字母,数字和标点符号使用一个字节。
- 大多数欧洲和中东脚本字母均以 2 字节的顺序排列:扩展的拉丁字母(带有波浪号,马克龙,尖刻,重音和其他重音符号),西里尔字母,希腊语,亚美尼亚语,希伯来语,阿拉伯语,叙利亚语等。
- 韩文,中文和日文 表意字符使用 3 字节或 4 字节序列。
MySQL 支持以下 Unicode 字符集:
- utf8mb4:Unicode 字符集的 UTF-8 编码,每个字符使用 1-4 个字节。
- utf8mb3:Unicode 字符集的 UTF-8 编码,每个字符使用一到三个字节。
- utf8:utf8mb3的别名。
- ucs2:Unicode 字符集的 UCS-2 编码,每个字符使用两个字节。
- utf16:Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2,但扩展了辅助字符。
- utf16le:Unicode 字符集的 UTF-16LE 编码。像utf16,但是小端而不是大端。
- utf32:Unicode 字符集的 UTF-32 编码,每个字符使用四个字节。
Unicode 字符集的一般特性
Character Set | Supported Characters | 每个字符所需的存储量 |
---|---|---|
utf8mb3 , utf8 | BMP only | 1,2 或 3 个字节 |
ucs2 | BMP only | 2 bytes |
utf8mb4 | BMP 和补充 | 1,2、3 或 4 个字节 |
utf16 | BMP 和补充 | 2 或 4 个字节 |
utf16le | BMP 和补充 | 2 或 4 个字节 |
utf32 | BMP 和补充 | 4 bytes |
- BMP 之外的字符将作为 REPLACEMENT CHARACTER 进行比较,并在转换为仅支持 BMP 字符(utf8mb3或ucs2)的 Unicode 字符集时转换为'?'。
- 如果您使用支持补充字符的字符集,并且比仅 BMP 的utf8mb3和ucs2字符集“宽”,则应用程序可能会出现不兼容的问题;
- 大多数 Unicode 字符集都可以使用类似的排序规则集。例如,每个都有丹麦语排序规则,其名称为 utf8mb4_danish_ci,utf8mb3_danish_ci,utf8_danish_ci,ucs2_danish_ci,utf16_danish_ci 和 utf32_danish_ci。
- (utf16le除外,它只有两个排序规则)
- UCS-2,UTF-16 和 UTF-32 的 MySQL 实现以大端字节序列存储字符,并且在值的开头不使用“字节序列标记”(BOM)。其他数据库系统可能使用低位字节序或 BOM。在这种情况下,在这些系统和 MySQL 之间传输数据时将需要执行值的转换。
- (UTF-16LE 的实现是小端的)
- MySQL 对 UTF-8 值不使用 BOM。
- 使用 Unicode 与服务器通信的 Client 端应用程序应相应地设置 Client 端字符集(例如,通过发出“SET NAMES 'utf8mb4'”语句)。某些字符集不能用作 Client 端字符集。
utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)
utfmb4字符集具有以下特征:
- 支持 BMP 和补充字符。
- 每个多字节字符最多需要四个字节。
utf8mb4 与 utf8mb3(仅支持 BMP 字符,每个字符最多使用三个字节)对比:
- 对于 BMP 字符,utf8mb4 和 utf8mb3 具有相同的存储特征:相同的代码值,相同的编码,相同的长度。
- 对于补充字符,utf8mb4 需要四个字节来存储它,而 utf8mb3 根本不能存储该字符。将 utf8mb3 列转换为 utf8mb4 时,您无需担心转换补充字符,因为将没有补充字符。
utf8mb4 是 utf8mb3 的超集,因此对于诸如以下操作,结果具有字符集 utf8mb4 和排序规则 utf8mb4_col:
SELECT CONCAT(utf8mb3_col, utf8mb4_col);
同样,WHERE 子句中的以下比较根据 utf8mb4_col 的排序规则起作用:
SELECT * FROM utf8mb3_tbl, utf8mb4_tbl
WHERE utf8mb3_tbl.utf8mb3_col = utf8mb4_tbl.utf8mb4_col;
utf8mb3(utf8)字符集(3 字节 UTF-8 Unicode 编码)
utf8mb3字符集具有以下特征:
- 仅支持 BMP 字符(不支持补充字符)
- 每个多字节字符最多需要三个字节。
- 使用 UTF-8 数据但需要辅助字符支持的应用程序应使用 utf8mb4 而不是 utf8mb3。
- utf8mb3 和 ucs2 中提供了完全相同的字符集。也就是说,它们具有相同的字符集。
- utf8 是 utf8mb3 的别名;字符限制是隐式的,而不是名称中的显式。
- utf8mb3 可用于“CHARACTER SET”子句,“utf8mb3_collation_substring”可用于“COLLATE”子句,其中“collation_substring”是:bin,czech_ci,danish_ci,esperanto_ci,estonian_ci等。例如:
CREATE TABLE t (s1 CHAR(1) CHARACTER SET utf8mb3; SELECT * FROM t WHERE s1 COLLATE utf8mb3_general_ci = 'x'; DECLARE x VARCHAR(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_danish_ci; SELECT CAST('a' AS CHAR CHARACTER SET utf8) COLLATE utf8_czech_ci;
- MySQL 立即将语句中的 utf8mb3 实例转换为 utf8,因此在诸如“SHOW CREATE TABLE”或“SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS”或“SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS”的语句中,用户将看到名称 utf8 或 utf8_collation_substring。
- utf8mb3在除“CHARACTER SET”子句之外的上下文中也有效。例如:
mysqld --character-set-server=utf8mb3
SET NAMES 'utf8mb3'; /* and other SET statements that have similar effect */ SELECT _utf8mb3 'a';
ucs2 字符集(UCS-2 Unicode 编码)
在 UCS-2 中,每个字符都由 2 字节 Unicode 代码表示,最高有效字节在前【大端存储】。例如:LATIN CAPITAL LETTER A的代码为0x0041,并存储为 2 字节序列:0x00 0x41。
ucs2 字符集具有以下特征:
- 仅支持 BMP 字符(不支持补充字符)。
- 使用固定长度的 16 位编码,每个字符需要两个字节。
utf16 字符集(UTF-16 Unicode 编码)、utf16le 字符集
utf16 字符集是支持补充字符的 ucs2字符集。
utf16 可以对补充字符进行编码:
- 对于 BMP 字符,utf16 和 ucs2 具有相同的存储特征:相同的代码值,相同的编码,相同的长度。
- 对于补充字符,utf16 使用具有 32 位表示字符的特殊序列。这称为“代替”机制:对于大于“0xffff”的数字,请使用 10 位并将其添加到“0xd800”并将其放置在第一个 16 位字中,再使用 10 位并将其添加到“0xdc00”并将其放置在下一个 16 位字。因此,所有补充字符都需要 32 位,其中前 16 位是“0xd800”和“0xdbff”之间的数字,而后 16 位是“0xdc00”和“0xdfff”之间的数字。
- utf16le:与utf16相同,但是是小端而不是大端存储。
utf32 字符集(UTF-32 Unicode 编码)
utf32 字符集是固定长度的:对每个字符使用 32 位。
utf32 字符集具有以下特征:
- utf32 的空间是 ucs2 的两倍,比 utf16的空间大,但是 utf32 与 ucs2 具有相同的优点,可以预测存储:utf32 的所需字节数等于字符数乘以 4。
- 此外,与utf16不同,在utf32中没有编码技巧,因此存储的值等于代码值。
- 对此,乐意在给定 utf32 代码值的情况下确定 utf8mb4 值:
/* Assume code value = 100cc LINEAR B WHEELED CHARIOT */ CREATE TABLE tmp (utf32_col CHAR(1) CHARACTER SET utf32, utf8mb4_col CHAR(1) CHARACTER SET utf8mb4); INSERT INTO tmp VALUES (0x000100cc,NULL); UPDATE tmp SET utf8mb4_col = utf32_col; SELECT HEX(utf32_col),HEX(utf8mb4_col) FROM tmp;
- MySQL 非常宽容地添加未分配的 Unicode 字符或专用区域字符。实际上,对 utf32 仅进行一次有效性检查:任何代码值都不能大于“0x10ffff”。例如,这是非法的:
INSERT INTO t (utf32_column) VALUES (0x110000); /* illegal */
在 3 字节和 4 字节 Unicode 字符集之间转换
- 主要集中在 utf8mb3 和 utf8mb4 之间的转换,但是类似的原理适用于 ucs2 字符集和诸如 utf16 或 utf32 之类的字符集之间的转换。
utf8mb3 和 utf8mb4 字符集的区别如下:
- utf8mb3 仅支持基本多语言平面(BMP)中的字符。 utf8mb4 还支持 BMP 之外的补充字符。
- utf8mb3 每个字符最多使用三个字节。 utf8mb4 每个字符最多使用四个字节。
- 从 utf8mb3 转换为 utf8mb4 的一个优点是,这使应用程序可以使用补充字符。一个缺点是这可能增加数据存储空间需求。
就 table 内容而言,从 utf8mb3 转换为 utf8mb4 不会出现问题:
- 对于 BMP 字符,utf8mb4 和 utf8mb3 具有相同的存储特征:相同的代码值,相同的编码,相同的长度。
- 对于补充字符,utf8mb4 需要四个字节来存储它,而 utf8mb3 根本不能存储该字符。将 utf8mb3 列转换为 utf8mb4 时,您无需担心转换补充字符,因为将没有补充字符。
就 table 结构而言,这些是潜在的主要不兼容性:
- 对于可变长度字符数据类型(VARCHAR 和 TEXT 类型),utf8mb4 列的字符允许的最大长度小于 utf8mb3 列的字符的最大允许长度。
- 对于所有字符数据类型(CHAR,VARCHAR和TEXT类型),utf8mb4 列的索引最大字符数少于 utf8mb3 列的索引数。
因此,要将 table 从 utf8mb3 转换为 utf8mb4,可能需要更改某些列或索引定义。在转换 MySQLtable 时请注意以下问题:
- 检查 utf8mb3 列的所有定义,并确保它们不会超过存储引擎的最大长度。
- 检查 utf8mb 3列上的所有索引,并确保它们不会超过存储引擎的最大长度。有时,由于存储引擎的增强,最大值可能会更改。
如果满足上述条件,则必须减少定义的列或索引的长度,或者继续使用 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))
- 【对于使用“COMPRESSED”或“DYNAMIC”行格式的InnoDB table,您可以启用“innodb_large_prefix”选项以允许索引键前缀长于 767 字节(最多 3072 字节)。在这种情况下,启用“innodb_large_prefix”选项可使您分别为 utf8mb3 或 utf8mb4 列索引最多 1024 个或 768 个字符。(创建此类 table 还需要选项值“innodb_file_format=barracuda”和“innodb_file_per_table=true”)】
可以使用“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;
如果您已转换为 utf8mb4,utf16,utf16le 或 utf32,然后决定转换回 utf8mb3 或 ucs2 (例如,降级到旧版本的 MySQL),则适用以下注意事项:
- utf8mb3 和 ucs2 数据应该没有问题。
- 服务器必须具有足够的最新性,以识别引用所要转换的字符集的定义。
- 对于引用 utf8mb4 字符集的对象定义,您可以在降级之前用 mysqldump 转储它们,编辑转储文件以将 utf8mb4 的实例更改为 utf8,然后在没有旧版本的服务器中重新加载文件,只要数据中没有 4 的字节字符。较旧的服务器将在转储文件对象定义中看到 utf8,并创建使用(3 字节)utf8字符集的新对象。