MySQL 字符集:Unicode 支持

来自Wikioe
Eijux讨论 | 贡献2021年3月29日 (一) 03:10的版本 →‎关于
跳到导航 跳到搜索


关于

Unicode 标准包括来自基本多语言平面(BMP)的字符和位于 BMP 之外的补充字符。【BMP,见关于:基本多语言平面(BMP)

BMP 字符具有以下特征:

  1. 它们的代码点值在 0 到 65535 之间(或 U+0000 和 U+FFFF)。
  2. 它们可以使用 8 位,16 位或 24 位(1 到 3 个字节)以可变长度编码进行编码。
  3. 它们可以使用 16 位(2 字节)以固定长度编码进行编码。
  4. 它们足以应付主要语言中的几乎所有字符。

补充字符位于 BMP 之外:

  1. 它们的代码点值在 U+10000 和 U+10FFFF 之间)。
  2. Unicode 对补充字符的支持要求字符集的范围超出 BMP 字符,因此比 BMP 字符占用更多的空间(每个字符最多 4 个字节)。
  • 【包括现在一些常用的表情字符,如果使用不支持补充字符集的实现(如使用“utf8mb3”,而非“utf8mb4”)可能导致不能使用表情符号】
    Unicode字符集中的Emoji表情字符.jpg


根据 RFC 3629 实现了用于对 Unicode 数据进行编码的 UTF-8(具有 8 位单位的 Unicode 转换格式)方法,该方法描述了从一到四个字节的编码序列。 UTF-8 的思想是使用不同长度的字节序列对各种 Unicode 字符进行编码:

  1. 基本的拉丁字母,数字和标点符号使用一个字节。
  2. 大多数欧洲和中东脚本字母均以 2 字节的顺序排列:扩展的拉丁字母(带有波浪号,马克龙,尖刻,重音和其他重音符号),西里尔字母,希腊语,亚美尼亚语,希伯来语,阿拉伯语,叙利亚语等。
  3. 韩文,中文和日文 表意字符使用 3 字节或 4 字节序列。


MySQL 支持以下 Unicode 字符集:

  1. utf8mb4:Unicode 字符集的 UTF-8 编码,每个字符使用 1-4 个字节。
  2. utf8mb3:Unicode 字符集的 UTF-8 编码,每个字符使用一到三个字节。
  3. utf8:utf8mb3的别名。
  4. ucs2:Unicode 字符集的 UCS-2 编码,每个字符使用两个字节。
  5. utf16:Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2,但扩展了辅助字符。
  6. utf16le:Unicode 字符集的 UTF-16LE 编码。像utf16,但是小端而不是大端。
  7. 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字符集具有以下特征:

  1. 支持 BMP 和补充字符。
  2. 每个多字节字符最多需要四个字节。


utf8mb4 与 utf8mb3(仅支持 BMP 字符,每个字符最多使用三个字节)对比:

  1. 对于 BMP 字符,utf8mb4 和 utf8mb3 具有相同的存储特征:相同的代码值,相同的编码,相同的长度。
  2. 对于补充字符,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字符集具有以下特征:

  1. 仅支持 BMP 字符(不支持补充字符)
  2. 每个多字节字符最多需要三个字节。
  • 使用 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 字符集具有以下特征:

  1. 仅支持 BMP 字符(不支持补充字符)。
  2. 使用固定长度的 16 位编码,每个字符需要两个字节。

utf16 字符集(UTF-16 Unicode 编码)、utf16le 字符集

utf16 字符集是支持补充字符的 ucs2字符集。

utf16 可以对补充字符进行编码:

  1. 对于 BMP 字符,utf16 和 ucs2 具有相同的存储特征:相同的代码值,相同的编码,相同的长度。
  2. 对于补充字符,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 字符集具有以下特征:

  1. utf32 的空间是 ucs2 的两倍,比 utf16的空间大,但是 utf32 与 ucs2 具有相同的优点,可以预测存储:utf32 的所需字节数等于字符数乘以 4
  2. 此外,与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 字符集的区别如下:

  1. utf8mb3 仅支持基本多语言平面(BMP)中的字符。 utf8mb4 还支持 BMP 之外的补充字符。
  2. utf8mb3 每个字符最多使用三个字节。 utf8mb4 每个字符最多使用四个字节。


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


就 table 内容而言,从 utf8mb3 转换为 utf8mb4 不会出现问题:

  1. 对于 BMP 字符,utf8mb4 和 utf8mb3 具有相同的存储特征:相同的代码值,相同的编码,相同的长度
  2. 对于补充字符,utf8mb4 需要四个字节来存储它,而 utf8mb3 根本不能存储该字符。将 utf8mb3 列转换为 utf8mb4 时,您无需担心转换补充字符,因为将没有补充字符。

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

  1. 对于可变长度字符数据类型(VARCHAR 和 TEXT 类型),utf8mb4 列的字符允许的最大长度小于 utf8mb3 列的字符的最大允许长度
  2. 对于所有字符数据类型(CHAR,VARCHAR和TEXT类型),utf8mb4 列的索引最大字符数少于 utf8mb3 列的索引数

因此,要将 table 从 utf8mb3 转换为 utf8mb4,可能需要更改某些列或索引定义。在转换 MySQLtable 时请注意以下问题:

  1. 检查 utf8mb3 列的所有定义,并确保它们不会超过存储引擎的最大长度。
  2. 检查 utf8mb 3列上的所有索引,并确保它们不会超过存储引擎的最大长度。有时,由于存储引擎的增强,最大值可能会更改。

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


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

  1. “TINYTEXT”列最多可容纳 255 个字节,因此最多可容纳 85 个 3 字节或 63 个 4 字节字符。
    假设您有一个使用 utf8mb3 的“TINYTEXT”列,但必须包含 63 个以上的字符。除非将数据类型更改为更长的类型,例如“TEXT”,否则不能将其转换为 utf8mb4。
    • 同样,如果要将“VARCHAR”较长的列从 utf8mb3 转换为 utf8mb4,则可能需要将其更改为较长的“TEXT”类型之一。
  2. 对于使用“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),则适用以下注意事项:

  1. utf8mb3 和 ucs2 数据应该没有问题。
  2. 服务器必须具有足够的最新性,以识别引用所要转换的字符集的定义。
  3. 对于引用 utf8mb4 字符集的对象定义,您可以在降级之前用 mysqldump 转储它们,编辑转储文件以将 utf8mb4 的实例更改为 utf8,然后在没有旧版本的服务器中重新加载文件,只要数据中没有 4 的字节字符。较旧的服务器将在转储文件对象定义中看到 utf8,并创建使用(3 字节)utf8字符集的新对象。