Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


12.10.1 Unicode 字符集

本节描述了 Unicode 字符集的可用排序规则及其区别性质。关于 Unicode 的一般信息,请参见第 12.9 节,“Unicode 支持”

MySQL 支持多种 Unicode 字符集:

  • utf8mb4:使用一个到四个字节表示 Unicode 字符集的 UTF-8 编码。

  • utf8mb3:使用一个到三个字节表示 Unicode 字符集的 UTF-8 编码。该字符集已弃用,建议使用 utf8mb4

  • utf8utf8mb3 的别名。请使用 utf8mb4

    Note

    utf8 将来版本中将变为 utf8mb4 的别名。

  • ucs2: Unicode 字符集的 UCS-2 编码,使用两个字节表示每个字符。已弃用,预计在未来 MySQL 版本中将被删除。

  • utf16: Unicode 字符集的 UTF-16 编码,使用两个或四个字节表示每个字符。与 ucs2 类似,但支持补充字符。

  • utf16le: Unicode 字符集的 UTF-16LE 编码。与 utf16 类似,但使用小端序。

  • utf32: Unicode 字符集的 UTF-32 编码,使用四个字节表示每个字符。

Note

警告:utf8mb3 字符集已弃用,未来 MySQL 版本中将被删除。请使用 utf8mb4 替代。utf8 目前是 utf8mb3 的别名,但现在已经被弃用,预计将来会变成 utf8mb4 的别名。utf8mb3 也在信息架构表的列和 SQL 语句的输出中显示为 utf8

为了避免关于 utf8 的含义歧义,考虑明确指定 utf8mb4 作为字符集引用。

utf8mb4utf16utf16leutf32 支持基本多语言平面(BMP)字符和超出 BMP 的补充字符。utf8mb3ucs2 只支持 BMP 字符。

大多数 Unicode 字符集都有一个通用排序(以名称中包含 _general 或缺少语言指定为标识),一个二进制排序(以名称中包含 _bin 为标识),还有几个语言特定的排序(以语言指定为标识)。例如,utf8mb4 的通用和二进制排序分别是 utf8mb4_general_ciutf8mb4_bin,而 utf8mb4_danish_ci 是其中一个语言特定的排序。

大多数字符集只有一个二进制排序。utf8mb4 是例外,它有两个:utf8mb4_binutf8mb4_0900_bin。这两个二进制排序的顺序相同,但通过 pad 属性和权重特征进行区分。见排序pad属性,和字符权重

utf16le 排序支持有限。只有 utf16le_general_ciutf16le_bin 两个排序可用。它们类似于 utf16_general_ciutf16_bin

MySQL 根据 Unicode 排序算法(UCA)描述在http://www.unicode.org/reports/tr10/实现了 xxx_unicode_ci 排序规则。该排序规则使用版本-4.0.0 UCA 权重键:http://www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txtxxx_unicode_ci 排序规则对 Unicode 排序算法只提供部分支持,某些字符不受支持,组合标记也不是完全支持。这影响了语言,如越南语、约鲁巴语和纳瓦霍语。一个组合字符被认为不同于同一个字符写成单个unicode 字符串比较中,并且这两个字符被认为有不同的长度(例如,返回CHAR_LENGTH() 函数或结果集元数据)。

基于 UCA 版本高于 4.0.0 的 Unicode 排序规则在排序规则名称中包含版本。示例:

LOWER()UPPER() 函数根据其参数的排序规则执行大小写折叠。使用 Unicode 版本高于 4.0.0 的字符只有在参数排序规则使用高于 4.0.0 的 UCA 版本时才被这些函数转换。

基于 UCA 9.0.0 及更高版本的排序规则比基于 UCA 9.0.0 之前的版本快。它们也具有NO PAD 属性,相比于基于 UCA 9.0.0 之前的版本使用的 PAD SPACE。对于非二进制字符串比较,NO PAD 排序规则将字符串末尾的空格视为其他字符(见比较时的空格处理)。

要确定排序规则的 pad 属性,可以使用 INFORMATION_SCHEMA COLLATIONS 表的PAD_ATTRIBUTE 列,例如:

mysql> SELECT COLLATION_NAME, PAD_ATTRIBUTE
       FROM INFORMATION_SCHEMA.COLLATIONS
       WHERE CHARACTER_SET_NAME = 'utf8mb4';
+----------------------------+---------------+
| COLLATION_NAME             | PAD_ATTRIBUTE |
+----------------------------+---------------+
| utf8mb4_general_ci         | PAD SPACE     |
| utf8mb4_bin                | PAD SPACE     |
| utf8mb4_unicode_ci         | PAD SPACE     |
| utf8mb4_icelandic_ci       | PAD SPACE     |
...
| utf8mb4_0900_ai_ci         | NO PAD        |
| utf8mb4_de_pb_0900_ai_ci   | NO PAD        |
| utf8mb4_is_0900_ai_ci      | NO PAD        |
...
| utf8mb4_ja_0900_as_cs      | NO PAD        |
| utf8mb4_ja_0900_as_cs_ks   | NO PAD        |
| utf8mb4_0900_as_ci         | NO PAD        |
| utf8mb4_ru_0900_ai_ci      | NO PAD        |
| utf8mb4_ru_0900_as_cs      | NO PAD        |
| utf8mb4_zh_0900_as_cs      | NO PAD        |
| utf8mb4_0900_bin           | NO PAD        |
+----------------------------+---------------+

非二进制字符串值(CHARVARCHARTEXT)具有NO PAD 排序规则与其他排序规则不同,例如,'a''a ' 将被视为不同的字符串,而不是同一个字符串。这可以使用 utf8mb4 的二进制排序来观察。utf8mb4_bin 排序规则的 pad 属性是 PAD SPACE,而 utf8mb4_0900_bin 排序规则的属性是 NO PAD。因此,对于 utf8mb4_0900_bin 的操作不添加尾部空格,涉及字符串尾部空格的比较结果可能不同:

mysql> CREATE TABLE t1 (c CHAR(10) COLLATE utf8mb4_bin);
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO t1 VALUES('a');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM t1 WHERE c = 'a ';
+------+
| c    |
+------+
| a    |
+------+
1 row in set (0.00 sec)

mysql> ALTER TABLE t1 MODIFY c CHAR(10) COLLATE utf8mb4_0900_bin;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t1 WHERE c = 'a ';
Empty set (0.00 sec)

MySQL 实现了语言特定的 Unicode 排序规则,如果基于 Unicode 排序算法(UCA)的排序不适用于某种语言。语言特定的排序规则是 UCA 基础上加语言定制规则。这些规则后面在本节中出现。关于特定语言排序的问题,http://unicode.org 提供了通用地区数据库(CLDR)排序图表,在 http://www.unicode.org/cldr/charts/30/collation/index.html 中可以找到。

例如,非语言特定的 utf8mb4_0900_ai_ci 和 语言特定的 utf8mb4_LOCALE_0900_ai_ci Unicode 排序规则都具有这些特征:

  • 该排序规则基于 UCA 9.0.0 和 CLDR v30,忽略音调和大小写。这些特征在排序名称中以 _0900_ai_ci 表示。例外:utf8mb4_la_0900_ai_ci 不基于 CLDR,因为古典拉丁语不在 CLDR 中定义。

  • 该排序规则适用于范围 [U+0, U+10FFFF] 的所有字符。

  • 如果排序规则不是语言特定的,它将按照默认顺序(以下描述)对所有字符进行排序。如果排序规则是语言特定的,它将根据语言特定规则正确地对语言字符进行排序,对于不在语言中的字符使用默认顺序。

  • 默认情况下,排序规则根据 DUCET 表(Default Unicode Collation Element Table)中分配的权重值对字符进行排序。对于没有在 DUCET 表中的字符,它们将使用隐式权重值,这个权重值根据 UCA 构建。

  • 对于非语言特定的排序规则,合约序列中的字符被视为单独的字符。对于语言特定的排序规则,合约可能会改变字符排序顺序。

包含locale代码或语言名称的排序规则名称是语言特定的排序规则。Unicode 字符集可能包括这些语言的排序规则。

表 12.3 Unicode 排序语言指定符

Language Language Specifier
波斯尼亚语 bs
保加利亚语 bg
中文 zh
古典拉丁语 laroman
克罗地亚语 hr克罗地亚语
捷克语 cs捷克语
丹麦语 da丹麦语
埃斯佩兰托语 eo埃斯佩兰托语
爱沙尼亚语 et爱沙尼亚语
加利西亚语 gl
德国电话簿顺序 de_pb德国2
匈牙利语 hu匈牙利语
冰岛语 is冰岛语
日语 ja
拉脱维亚语 lv拉脱维亚语
立陶宛语 lt立陶宛语
蒙古语 mn
挪威语 / 书面语 nb
挪威语 / 新挪威语 nn
波斯语 波斯语
波兰语 pl波兰语
罗马尼亚语 ro罗马尼亚
俄罗斯 ru
塞尔维亚 sr
僧伽罗 sinhala
斯洛伐克 sk斯洛伐克
斯洛文尼亚 sl斯洛文尼亚
现代西班牙 es西班牙
传统西班牙 es_trad西班牙2
瑞典 sv瑞典
土耳其 tr土耳其
越南 vi越南

MySQL 提供了 utf8mb4_bg_0900_ai_ci 和 utf8mb4_bg_0900_as_cs 这两个保加利亚编码。

克罗地亚编码是为这些克罗地亚字母而设计的:ČĆĐLjNjŠŽ.

MySQL 提供了用于塞尔维亚语和波斯尼亚语的utf8mb4_sr_latn_0900_ai_ciutf8mb4_sr_latn_0900_as_cs 排序规则,以及用于波黑语的utf8mb4_bs_0900_ai_ciutf8mb4_bs_0900_as_cs 排序规则,用于这些语言使用拉丁字母。

MySQL 对于挪威语提供了两个主要变体的排序规则:对于布克马尔语,可以使用utf8mb4_nb_0900_ai_ciutf8mb4_nb_0900_as_cs;对于尼诺斯克语,MySQL 现在提供了utf8mb4_nn_0900_ai_ciutf8mb4_nn_0900_as_cs

对于日语,utf8mb4 字符集包括utf8mb4_ja_0900_as_csutf8mb4_ja_0900_as_cs_ks 排序规则。两个排序规则都是音调敏感的和大小写敏感的。utf8mb4_ja_0900_as_cs_ks 还是片假名敏感,区分片假名字符和平假名字符,而utf8mb4_ja_0900_as_cs 对片假名和平假名字符进行排序视为等价。需要日语排序规则但不需要片假名敏感的应用程序可以使用 utf8mb4_ja_0900_as_cs,以提高排序性能。utf8mb4_ja_0900_as_cs 对于排序使用三个权重级别,而utf8mb4_ja_0900_as_cs_ks 使用四个。

对于古典拉丁语的不敏感排序,IJ 作为等价,UV 也作等价。IJUV 在基础字母级别上作等价。换言之,J 被视为带点的 IU 被视为带点的 V

MySQL 提供了使用西里尔字母书写蒙古语的排序,包括 utf8mb4_mn_cyrl_0900_ai_ciutf8mb4_mn_cyrl_0900_as_cs

西班牙语排序可用于现代和传统西班牙语。对于两者,ñ(n-tilde) 在 no 之间作单独字母。此外,对于传统西班牙语,chcd 之间作单独字母,lllm 之间也作单独字母。

传统西班牙语排序也可用于阿斯图里亚斯和加利西亚语。MySQL 还提供了 utf8mb4_gl_0900_ai_ciutf8mb4_gl_0900_as_cs 排序以供加利西亚语使用。(这些排序与 utf8mb4_es_0900_ai_ciutf8mb4_es_0900_as_cs 相同,分别。)

瑞典语排序包括瑞典语规则。例如,在瑞典语中,以下关系成立,这并不是德国或法语发音者所期望的:

Ü = Y < Ö

对于任何 Unicode 字符集,使用 xxx_general_ci 排序规则执行的操作都比使用 xxx_unicode_ci 排序规则快,但不太准确。例如,utf8mb4_general_ci 排序规则的比较速度更快,但是略微不正确,而 utf8mb4_unicode_ci 排序规则的比较速度较慢,但更加准确。原因是 utf8mb4_unicode_ci 支持映射,如扩展;例如,ß 等于 ss 在德语和一些其他语言中。utf8mb4_unicode_ci 还支持合并和忽略字符。utf8mb4_general_ci 是一个遗留排序规则,不支持扩展、合并或忽略字符,只能进行一对一的比较。

为了更好地解释,以下等式在 utf8mb4_general_ciutf8mb4_unicode_ci 中都成立(关于比较或搜索的效果,请参见第12.8.6节,“排序规则的示例”):

Ä = A
Ö = O
Ü = U

两个排序规则之间的一个差异是:

ß = s

而这个是 utf8mb4_unicode_ci 排序规则支持德语 DIN-1 排序(也称字典顺序):

ß = ss

MySQL 如果语言特定的 Unicode 排序与utf8mb4_unicode_ci不佳,实现语言特定的 Unicode 排序。例如,utf8mb4_unicode_ci 对德语字典顺序和法语都很好,所以不需要创建特殊的utf8mb4 排序。

utf8mb4_general_ci 对德语和法语也都满意,除了ß 等于 s,而不是ss。如果这不可接受(例如,如果您需要德语字典顺序),使用utf8mb4_unicode_ci,因为它更准确。如果这可接受(例如,如果您的应用程序要求速度),使用utf8mb4_general_ci,因为它更快。

如果您需要德语 DIN-2 (电话簿) 排序,使用utf8mb4_german2_ci 排序,它将比较以下字符集等价:

Ä = Æ = AE
Ö = Œ = OE
Ü = UE
ß = ss

utf8mb4_german2_ci 类似于 latin1_german2_ci,但是后者不将Æ 等于 AEŒ 等于 OE。没有对应的utf8mb4_german_ci 排序,因为utf8mb4_general_ci 已经足够。

一个字符的排序权重是按照以下方式确定的:

  • 除了_bin(二进制) 排序外,MySQL 都会执行表lookup 来找到一个字符的排序权重。

  • 对于除 utf8mb4_0900_bin 之外的 _bin 排序,权重基于代码点,可能添加前导零字节。

  • 对于 utf8mb4_0900_bin,权重是 utf8mb4 编码字节。排序顺序与 utf8mb4_bin 一致,但速度更快。

可以使用WEIGHT_STRING()函数显示排序权重。 (参见第14.8节,“字符串函数和操作符”。)如果排序使用权重查找表,但字符不在表中(例如,因为它是字符),则排序权重确定变得更加复杂:

  • 对于一般排序 (xxx_general_ci),权重是代码点。

  • 对于 UCA 排序(例如,xxx_unicode_ci 和语言特定的排序),以下算法适用:

    if (code >= 0x3400 && code <= 0x4DB5)
      base= 0xFB80; /* CJK Ideograph Extension */
    else if (code >= 0x4E00 && code <= 0x9FA5)
      base= 0xFB40; /* CJK Ideograph */
    else
      base= 0xFBC0; /* All other characters */
    aaaa= base +  (code >> 15);
    bbbb= (code & 0x7FFF) | 0x8000;

    结果是一个顺序的两个排序元素,aaaa 后跟 bbbb。例如:

    mysql> SELECT HEX(WEIGHT_STRING(_ucs2 0x04CF COLLATE ucs2_unicode_ci));
    +----------------------------------------------------------+
    | HEX(WEIGHT_STRING(_ucs2 0x04CF COLLATE ucs2_unicode_ci)) |
    +----------------------------------------------------------+
    | FBC084CF                                                 |
    +----------------------------------------------------------+

    因此,U+04cf CYRILLIC SMALL LETTER PALOCHKA (ӏ) 在所有 UCA 4.0.0 排序中大于 U+04c0 CYRILLIC LETTER PALOCHKA (Ӏ). 使用 UCA 5.2.0 排序,所有帕洛查排序一起。

  • 通用排序集中的补充字符的权重是 0xfffd REPLACEMENT CHARACTER。UCA 4.0.0 排序集中的补充字符的权重为 0xfffd。也就是说,对 MySQL 来说,所有补充字符都相等,且大于几乎所有 BMP 字符。

    一个使用 Deseret 字符和 COUNT(DISTINCT) 的示例:

    CREATE TABLE t (s1 VARCHAR(5) CHARACTER SET utf32 COLLATE utf32_unicode_ci);
    INSERT INTO t VALUES (0xfffd);   /* REPLACEMENT CHARACTER */
    INSERT INTO t VALUES (0x010412); /* DESERET CAPITAL LETTER BEE */
    INSERT INTO t VALUES (0x010413); /* DESERET CAPITAL LETTER TEE */
    SELECT COUNT(DISTINCT s1) FROM t;

    结果是 2,因为在 MySQL 中的 xxx_unicode_ci 排序集,替换字符的权重为 0x0dc6,而 Deseret Bee 和 Deseret Tee 都有权重为 0xfffd。(如果使用了 utf32_general_ci 排序集,结果是 1,因为三个字符都有权重为 0xfffd 在该排序集中。)

    一个使用库珊文字和 WEIGHT_STRING() 的示例:

    /*
    The four characters in the INSERT string are
    00000041  # LATIN CAPITAL LETTER A
    0001218F  # CUNEIFORM SIGN KAB
    000121A7  # CUNEIFORM SIGN KISH
    00000042  # LATIN CAPITAL LETTER B
    */
    CREATE TABLE t (s1 CHAR(4) CHARACTER SET utf32 COLLATE utf32_unicode_ci);
    INSERT INTO t VALUES (0x000000410001218f000121a700000042);
    SELECT HEX(WEIGHT_STRING(s1)) FROM t;

    结果是:

    0E33 FFFD FFFD 0E4A

    0E330E4A 是在 UCA 4.0.0 的主要权重。FFFD 是 KAB 和 KISH 的权重。

    所有补充字符相等的规则不是最优选择,但不太可能引起问题。这些字符很少,所以很少有多字符字符串完全由补充字符组成。在日本,既然这些补充字符是隐蔽的汉字 ideographs,典型用户并不关心它们的顺序。如果你真的想按 MySQL 规则和次要按代码点值排序,可以这样:

    ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin
  • 对于基于 UCA 版本高于 4.0.0 的补充字符(例如,xxx_unicode_520_ci),补充字符不一定都具有相同的排序权重。一些字符从 UCA 文件 allkeys.txt 中获取明确的权重,其他字符则根据以下算法计算权重:

    aaaa= base +  (code >> 15);
    bbbb= (code & 0x7FFF) | 0x8000;

存在“按字符代码值排序”和“按字符二进制表示排序”的差异,这种差异只在 utf16_bin 中出现,因为有 surrogate。

假设 utf16_binutf16 的二进制排序)是“字节-by-字节”而不是“字符-by-字符”。如果那样,那么 utf16_bin 中的字符顺序将不同于 utf8mb4_bin。例如,以下表格显示两个罕见字符。第一个字符在范围 E000-FFFF 内,所以它大于 surrogate 但小于补充字符。第二个字符是补充字符。

Code point  Character                    utf8mb4      utf16
----------  ---------                    -------      -----
0FF9D       HALFWIDTH KATAKANA LETTER N  EF BE 9D     FF 9D
10384       UGARITIC LETTER DELTA        F0 90 8E 84  D8 00 DF 84

表格中的两个字符按代码点值排序,因为 0xff9d 小于 0x10384。它们也按 utf8mb4 值排序,因为 0xef 小于 0xf0。但是,如果我们使用字节-by-字节比较,那么它们不在 utf16 值顺序中,因为 0xff 大于 0xd8

因此,MySQL 的 utf16_bin 排序不是字节-by 字节. 它是按代码点. 当 MySQL 看到 utf16 编码时,它将其转换为字符的代码点值,然后比较。因此,utf8mb4_binutf16_bin 排序是一致的。这与 SQL:2008 标准对 UCS_BASIC 排序的要求一致:UCS_BASIC 是一个在字符串排序中由字符 Unicode 字符值确定的排序。它适用于 UCS 字符库。由于每个字符库都是 UCS 库的子集,UCS_BASIC 排序可能适用于每个字符集。注意 11:字符的 Unicode 字符值是其代码点视为无符号整数.

如果字符集是 ucs2,比较是字节-by 字节,但是 ucs2 字符串不应该包含代理项。

The xxx_general_mysql500_ci 排序保留了原始 xxx_general_ci 排序的前 5.1.24 版本,并允许在 MySQL 5.1.24 之前的表创建升级(Bug #27877)。