文档首页
MySQL 9.0 参考手册
相关文档 下载此手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


12.10.1 Unicode 字符集

本节介绍适用于 Unicode 字符集的排序规则及其差异特性。有关 Unicode 的一般信息,请参阅 第 12.9 节 “Unicode 支持”.

MySQL 支持多种 Unicode 字符集

  • utf8mb4: 使用每个字符 1 到 4 个字节对 Unicode 字符集进行 UTF-8 编码。

  • utf8mb3: 使用每个字符 1 到 3 个字节对 Unicode 字符集进行 UTF-8 编码。此字符集已弃用;请改用 utf8mb4

  • utf8: utf8mb3 的已弃用别名。请改用 utf8mb4

    注意

    预计在将来的某个版本中,utf8 将成为 utf8mb4 的别名。

  • ucs2: 使用每个字符 2 个字节对 Unicode 字符集进行 UCS-2 编码。已弃用;预计将在 MySQL 的未来版本中移除对该字符集的支持。

  • utf16: 使用每个字符 2 或 4 个字节对 Unicode 字符集进行 UTF-16 编码。类似于 ucs2,但扩展了对补充字符的支持。

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

  • utf32: 使用每个字符 4 个字节对 Unicode 字符集进行 UTF-32 编码。

注意

utf8mb3 字符集已弃用,您应该预计它将在 MySQL 的未来版本中移除。请改用 utf8mb4。目前,utf8utf8mb3 的别名,但现在已弃用此别名,并且 utf8 预计随后将成为对 utf8mb4 的引用。在 Information Schema 表的列中,以及在 SQL SHOW 语句的输出中,utf8mb3 也将显示为 utf8 的替代。

为了避免对 utf8 的含义产生歧义,请考虑显式地为字符集引用指定 utf8mb4

utf8mb4utf16utf16leutf32 支持基本多语言平面 (BMP) 字符和位于 BMP 之外的补充字符。 utf8mb3ucs2 仅支持 BMP 字符。

大多数 Unicode 字符集都具有通用排序规则(在名称中以 _general 表示,或不指定语言说明符)、二进制排序规则(在名称中以 _bin 表示)和多个特定于语言的排序规则(以语言说明符表示)。例如,对于 utf8mb4utf8mb4_general_ciutf8mb4_bin 分别是其通用和二进制排序规则,而 utf8mb4_danish_ci 是其特定于语言的排序规则之一。

大多数字符集都只有一个二进制排序规则。 utf8mb4 是一个例外,它有两个:utf8mb4_binutf8mb4_0900_bin。这两个二进制排序规则具有相同的排序顺序,但它们的区别在于填充属性和排序权重特征。请参阅 排序规则填充属性,以及 字符排序权重.

utf16le 的排序规则支持有限。可用的排序规则仅限于 utf16le_general_ciutf16le_bin。它们类似于 utf16_general_ciutf16_bin

Unicode 排序算法 (UCA) 版本

MySQL 按照 http://www.unicode.org/reports/tr10/ 中描述的 Unicode 排序算法 (UCA) 实现 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() 函数返回,或在结果集元数据中)。

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

LOWER()UPPER() 函数根据其参数的排序规则执行大小写转换。只有当参数排序规则使用足够高的 UCA 版本时,这些函数才会转换只有在高于 4.0.0 的 Unicode 版本中才具有大写和小写形式的字符。

排序规则填充属性

基于 UCA 9.0.0 及更高版本的排序规则比基于 UCA 9.0.0 之前版本的排序规则速度更快。它们还具有 NO PAD 填充属性,而基于 UCA 9.0.0 之前版本的排序规则使用的是 PAD SPACE。对于非二进制字符串的比较,NO 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 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)

特定语言排序规则

如果仅基于 Unicode 排序算法 (UCA) 的排序对于某种语言效果不佳,MySQL 会实现特定语言的 Unicode 排序规则。特定语言的排序规则是基于 UCA 的,并具有额外的语言定制规则。此类规则的示例将在本节稍后介绍。有关特定语言排序的疑问,http://unicode.orghttp://www.unicode.org/cldr/charts/30/collation/index.html 提供了通用语言数据存储库 (CLDR) 排序图表。

例如,非特定语言的 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 表(默认 Unicode 排序元素表)中列出的代码点的字符进行排序,并根据表中分配的权重值进行排序。排序规则使用其隐式权重值对 DUCET 表中未列出代码点的字符进行排序,该值是根据 UCA 构造的。

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

包含以下表格中显示的区域设置代码或语言名称的排序规则名称是特定语言的排序规则。Unicode 字符集可能包含针对这些语言中的一种或多种语言的排序规则。

表 12.3 Unicode 排序语言说明符

语言 语言说明符
波斯尼亚语 bs
保加利亚语 bg
中文 zh
经典拉丁语 laroman
克罗地亚语 hrcroatian
捷克语 csczech
丹麦语 dadanish
世界语 eoesperanto
爱沙尼亚语 etestonian
加利西亚语 gl
德语电话簿顺序 de_pbgerman2
匈牙利语 huhungarian
冰岛语 isicelandic
日语 ja
拉脱维亚语 lvlatvian
立陶宛语 ltlithuanian
蒙古语 mn
挪威语/博克马尔 nb
挪威语/新挪威语 nn
波斯语 persian
波兰语 plpolish
罗马尼亚语 roromanian
俄语 ru
塞尔维亚语 sr
僧伽罗语 sinhala
斯洛伐克语 skslovak
斯洛文尼亚语 slslovenian
现代西班牙语 esspanish
传统西班牙语 es_tradspanish2
瑞典语 svswedish
土耳其语 trturkish
越南语 vivietnamese

MySQL 提供保加利亚语排序规则 utf8mb4_bg_0900_ai_ciutf8mb4_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 被视为相等。 IJ 以及 UV 在基本字母级别被视为相等。换句话说,J 被视为带有重音的 IU 被视为带有重音的 V

MySQL 为使用西里尔字母书写的蒙古语提供了排序规则,即 utf8mb4_mn_cyrl_0900_ai_ciutf8mb4_mn_cyrl_0900_as_cs

西班牙语排序规则适用于现代西班牙语和传统西班牙语。对于两者,ñ(带波浪线的 n)是 no 之间的单独字母。此外,对于传统西班牙语,chcd 之间的单独字母,lllm 之间的单独字母。

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

瑞典语排序规则包括瑞典语规则。例如,在瑞典语中,以下关系成立,这与德语或法语使用者预期的不同

Ü = Y < Ö

_general_ci 与 _unicode_ci 排序规则

对于任何 Unicode 字符集,使用 xxx_general_ci 排序规则执行的操作比 xxx_unicode_ci 排序规则执行的操作快。例如,utf8mb4_general_ci 排序规则的比较速度更快,但准确性略低,而 utf8mb4_unicode_ci 的比较速度略慢,但准确性更高。原因是 utf8mb4_unicode_ci 支持映射,例如扩展;也就是说,当一个字符与其他字符的组合比较相等时。例如,在德语和其他一些语言中,ß 等于 ssutf8mb4_unicode_ci 还支持收缩和可忽略字符。 utf8mb4_general_ci 是一个遗留排序规则,不支持扩展、收缩或可忽略字符。它只能对字符进行一对一比较。

为了进一步说明,以下等式在 utf8mb4_general_ciutf8mb4_unicode_ci 中都成立(有关其在比较或搜索中的影响,请参阅 第 12.8.6 节,“排序规则影响示例”

Ä = A
Ö = O
Ü = U

排序规则之间的区别在于,这对 utf8mb4_general_ci 来说是正确的

ß = s

而这对支持德语 DIN-1 排序(也称为字典排序)的 utf8mb4_unicode_ci 来说是正确的

ß = ss

如果使用 utf8mb4_unicode_ci 进行排序对于某种语言效果不佳,MySQL 会实现特定语言的 Unicode 排序规则。例如,utf8mb4_unicode_ci 适用于德语字典排序和法语,因此无需创建特殊的 utf8mb4 排序规则。

utf8mb4_general_ci 也适用于德语和法语,只是 ß 等于 s,而不是 ss。如果这对您的应用程序来说是可以接受的,您应该使用 utf8mb4_general_ci,因为它速度更快。如果这不可接受(例如,如果您需要德语字典排序),请使用 utf8mb4_unicode_ci,因为它更准确。

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

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

utf8mb4_german2_ci 类似于 latin1_german2_ci,但后者不会将 ÆAEŒOE 比较为相等。没有与德语字典排序的 latin1_german_ci 相对应的 utf8mb4_german_ci,因为 utf8mb4_general_ci 就足够了。

字符排序权重

字符的排序权重按如下方式确定

  • 对于除 _bin(二进制)排序规则以外的所有 Unicode 排序规则,MySQL 会执行表查找以查找字符的排序权重。

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

  • 对于 utf8mb4_0900_bin,权重是 utf8mb4 编码字节。排序顺序与 utf8mb4_bin 相同,但速度快得多。

可以使用 WEIGHT_STRING() 函数显示排序权重。(请参阅 第 14.8 节,“字符串函数和运算符”。)如果排序规则使用权重查找表,但表中不存在某个字符(例如,因为它是一个 字符),则确定排序权重会变得更加复杂

  • 对于一般排序规则 (xxx_general_ci) 中的 BMP 字符,权重是代码点。

  • 对于 UCA 排序规则(例如,xxx_unicode_ci 和特定语言的排序规则)中的 BMP 字符,以下算法适用

    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 的权重。

    所有补充字符彼此相等的规则并非最佳,但预计不会造成麻烦。这些字符非常罕见,因此由补充字符组成的多字符字符串也很罕见。在日本,由于补充字符是晦涩难懂的汉字,因此普通用户并不关心它们的排序方式。如果您确实希望按 MySQL 规则进行排序,并按代码点值进行二次排序,则非常简单。

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

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

“按字符代码值排序”和“按字符的二进制表示排序”之间存在差异,这种差异仅在 utf16_bin 中出现,这是由于代理字符造成的。

假设 utf16_binutf16 的二进制排序)是一个二进制比较“逐字节”而不是“逐字符”。如果是这样,则 utf16_bin 中字符的顺序将不同于 utf8mb4_bin 中的顺序。例如,下表显示了两个罕见的字符。第一个字符位于 E000-FFFF 范围内,因此它大于代理字符,但小于补充字符。第二个字符是补充字符。

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。但如果我们使用逐字节比较,它们不会按 utf16 值排序,因为 0xff > 0xd8

因此,MySQL 的 utf16_bin 排序不是“逐字节”。它是“按代码点”。当 MySQL 在 utf16 中看到补充字符编码时,它会转换为字符的代码点值,然后进行比较。因此,utf8mb4_binutf16_bin 的排序相同。这与 SQL:2008 标准对 UCS_BASIC 排序的要求一致:“UCS_BASIC 是一种排序,其中排序完全由要排序字符串中字符的 Unicode 标量值决定。它适用于 UCS 字符集。由于每个字符集都是 UCS 字符集的子集,因此 UCS_BASIC 排序可能适用于每个字符集。注意 11:字符的 Unicode 标量值是将其代码点视为无符号整数。”

如果字符集为 ucs2,则比较为逐字节,但 ucs2 字符串不应该包含代理字符。

其他信息

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