本节描述了 Unicode 字符集的可用排序规则及其区别特性。有关 Unicode 的一般信息,请参阅 第 12.9 节,“Unicode 支持”。
MySQL 支持多种 Unicode 字符集:
-
utf8mb4
:使用 1 到 4 个字节 per 字符的 Unicode 字符集的 UTF-8 编码。 -
utf8mb3
:使用 1 到 3 个字节 per 字符的 Unicode 字符集的 UTF-8 编码。此字符集已弃用;请使用utf8mb4
代替。 -
utf8
:一个弃用的别名为utf8mb3
。请使用utf8mb4
代替。Noteutf8
预计在未来版本中将成为utf8mb4
的别名。 -
ucs2
:Unicode 字符集的 UCS-2 编码,使用 2 个字节 per 字符。弃用;预计在未来版本中删除对该字符集的支持。 -
utf16
:Unicode 字符集的 UTF-16 编码,使用 2 或 4 个字节 per 字符。类似于ucs2
,但具有补充字符的扩展。 -
utf16le
:Unicode 字符集的 UTF-16LE 编码。类似于utf16
,但小端序而不是大端序。 -
utf32
:Unicode 字符集的 UTF-32 编码,使用 4 个字节 per 字符。
字符集 utf8mb3
已弃用,您应该期望在未来 MySQL 版本中删除它。请使用 utf8mb4
代替。utf8
目前是 utf8mb3
的别名,但它现在已弃用,utf8
预计将来将成为 utf8mb4
的引用。utf8mb3
也将在信息模式表的列和 SQL SHOW
语句的输出中显示为 utf8
。
为了避免关于 utf8
的歧义,请考虑明确指定 utf8mb4
作为字符集引用。
utf8mb4
、utf16
、utf16le
和 utf32
支持基本多语言平面(BMP)字符和超出 BMP 的补充字符。utf8mb3
和 ucs2
只支持 BMP 字符。
大多数 Unicode 字符集都有一个通用排序(在名称中以 _general
指示或没有语言指定符),一个二进制排序(在名称中以 _bin
指示),以及多种语言特定的排序(以语言指定符指示)。例如,对于 utf8mb4
,utf8mb4_general_ci
和 utf8mb4_bin
是其通用和二进制排序,而 utf8mb4_danish_ci
是其语言特定排序之一。
大多数字符集只有一个二进制排序。utf8mb4
是一个例外,它有两个:utf8mb4_bin
和 utf8mb4_0900_bin
。这两个二进制排序具有相同的排序顺序,但它们的填充属性和排序权重特征不同。请参阅 排序填充属性 和 字符排序权重。
对 utf16le
的排序支持有限。只有 utf16le_general_ci
和 utf16le_bin
两个排序可用。它们与 utf16_general_ci
和 utf16_bin
相似。
MySQL 根据 Unicode 排序算法(UCA)描述在 http://www.unicode.org/reports/tr10/ 实现了
排序。该排序使用版本 4.0.0 UCA 权重键:http://www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt。 xxx
_unicode_ci
排序仅部分支持 Unicode 排序算法。一些字符不受支持,组合标记也不完全支持。这影响了诸如越南语、约鲁巴语和纳瓦霍语等语言。组合字符被认为与使用单个 Unicode 字符编写的字符不同,在字符串比较中,并且这两个字符被认为具有不同的长度(例如,由 xxx
_unicode_ciCHAR_LENGTH()
函数或在结果集元数据中返回)。
基于 UCA 高于 4.0.0 版本的 Unicode 排序在排序名称中包括版本。例如:
-
utf8mb4_unicode_520_ci
基于 UCA 5.2.0 权重键:http://www.unicode.org/Public/UCA/5.2.0/allkeys.txt, -
utf8mb4_0900_ai_ci
基于 UCA 9.0.0 权重键:http://www.unicode.org/Public/UCA/9.0.0/allkeys.txt。
LOWER()
和 UPPER()
函数根据其参数的排序执行大小写折叠。如果字符只有在 Unicode 版本高于 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 |
+----------------------------+---------------+
非二进制字符串值(CHAR
、VARCHAR
和 TEXT
)的比较,具有 NO PAD
排序的字符串与其他排序不同,例如,'a'
和 'a '
比较为不同的字符串,而不是相同的字符串。这可以使用 utf8mb4 的二进制排序来看到。utf8mb4_bin 的 pad 属性为 PAD SPACE
,而 utf8mb4_0900_bin 的 pad 属性为 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_
Unicode 排序各具有以下特征:LOCALE
_0900_ai_ci
-
该排序基于 UCA 9.0.0 和 CLDR v30,是不区分重音和大小写的。这些特征由
_0900
、_ai
和_ci
在排序名称中表示。例外:utf8mb4_la_0900_ai_ci
不基于 CLDR,因为古典拉丁语在 CLDR 中未定义。 -
该排序适用于 Unicode 范围 [U+0, U+10FFFF] 中的所有字符。
-
如果排序不是语言特定的,则所有字符,包括补充字符,在默认顺序中排序。如果排序是语言特定的,则根据语言特定规则正确地排序语言中的字符,并在默认顺序中排序语言外的字符。
-
默认情况下,排序将根据 DUCET 表(默认 Unicode 排序元素表)中列出的代码点的权重值进行排序。对于不在 DUCET 表中的代码点,排序将使用隐式权重值,该值根据 UCA 构造。
-
对于非语言特定的排序,收缩序列中的字符将被视为单个字符。对于语言特定的排序,收缩可能会改变字符的排序顺序。
包含语言代码或语言名称的排序名称是语言特定的排序。 Unicode 字符集可能包括一个或多个语言的排序。
表 12.3 Unicode 排序语言指定符
Language | Language Specifier |
---|---|
波斯尼亚语 | bs |
保加利亚语 | bg |
中文 | zh |
古典拉丁语 | la 或 roman |
克罗地亚语 | hr 或 croatian |
捷克语 | cs 或 czech |
丹麦语 | da 或 danish |
世界语 | eo 或 esperanto |
爱沙尼亚语 | et 或 estonian |
加利西亚语 | gl |
德国电话簿顺序 | de_pb 或 german2 |
匈牙利语 | hu 或 hungarian |
冰岛语 | is 或 icelandic |
日语 | ja |
拉脱维亚语 | lv 或 latvian |
立陶宛语 | lt 或 lithuanian |
蒙古语 | mn |
挪威语 / 书面挪威语 | nb |
挪威语 / 新挪威语 | nn |
波斯语 | persian |
波兰语 | pl 或 polish |
罗马尼亚语 | ro 或 romanian |
俄语 | ru |
塞尔维亚语 | sr |
僧伽罗语 | sinhala |
斯洛伐克语 | sk 或 斯洛伐克语 |
斯洛文尼亚语 | sl 或 斯洛文尼亚语 |
现代西班牙语 | es 或 西班牙语 |
传统西班牙语 | es_trad 或 西班牙语2 |
瑞典语 | sv 或 瑞典语 |
土耳其语 | tr 或 土耳其语 |
越南语 | vi 或 越南语 |
MySQL 提供了保加利亚排序规则 utf8mb4_bg_0900_ai_ci
和 utf8mb4_bg_0900_as_cs
。
克罗地亚排序规则是为克罗地亚字母 Č
、Ć
、Dž
、Đ
、Lj
、Nj
、Š
、Ž
而设计的。
MySQL 提供了塞尔维亚语和波斯尼亚语的拉丁字母排序规则:utf8mb4_sr_latn_0900_ai_ci
和 utf8mb4_sr_latn_0900_as_cs
用于塞尔维亚语,utf8mb4_bs_0900_ai_ci
和 utf8mb4_bs_0900_as_cs
用于波斯尼亚语。
MySQL 提供了挪威语的两种主要变体的排序规则:对于布克莫尔语,可以使用 utf8mb4_nb_0900_ai_ci
和 utf8mb4_nb_0900_as_cs
;对于尼诺斯克语,MySQL 现在提供 utf8mb4_nn_0900_ai_ci
和 utf8mb4_nn_0900_as_cs
。
对于日本语,utf8mb4
字符集包括 utf8mb4_ja_0900_as_cs
和 utf8mb4_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
使用四个权重级别。
对于经典拉丁语排序,accent-insensitive,I
和 J
比较相等,U
和 V
比较相等。I
和 J
,以及 U
和 V
在基本字母级别上比较相等。换言之,J
被视为带音标的 I
,U
被视为带音标的 V
。
MySQL 提供了蒙古语 Cyrillic 字符集的排序,utf8mb4_mn_cyrl_0900_ai_ci
和 utf8mb4_mn_cyrl_0900_as_cs
。
西班牙语排序可用于现代和传统西班牙语。对于这两种,ñ
(ñ)是介于 n
和 o
之间的独立字母。此外,对于传统西班牙语,ch
是介于 c
和 d
之间的独立字母,ll
是介于 l
和 m
之间的独立字母。
传统西班牙语排序也可以用于阿斯图里亚斯语和加利西亚语。MySQL 还提供了 utf8mb4_gl_0900_ai_ci
和 utf8mb4_gl_0900_as_cs
排序用于加利西亚语。(这些排序与 utf8mb4_es_0900_ai_ci
和 utf8mb4_es_0900_as_cs
相同。)
瑞典语排序包括瑞典语规则。例如,在瑞典语中,以下关系成立,这不是德语或法语speaker所期望的:
Ü = Y < Ö
对于任何 Unicode 字符集,使用
排序的操作比使用 xxx
_general_ci
排序的操作要快。例如,xxx
_unicode_ciutf8mb4_general_ci
排序的比较比 utf8mb4_unicode_ci
排序的比较要快,但略微不那么正确。原因是 utf8mb4_unicode_ci
支持扩展映射,例如德语和其他语言中的 ß
等于 ss
。 utf8mb4_unicode_ci
也支持收缩和可忽略字符。utf8mb4_general_ci
是一个遗留排序,不支持扩展映射、收缩或可忽略字符。它只能进行一对一的字符比较。
另外,以下等式在 utf8mb4_general_ci
和 utf8mb4_unicode_ci
中都成立(对于比较或搜索的效果,请参阅 第 12.8.6 节,“collation 的效果示例”):
Ä = A
Ö = O
Ü = U
这两个 collation 之间的一个区别是,以下等式在 utf8mb4_general_ci
中成立:
ß = s
而以下等式在 utf8mb4_unicode_ci
中成立,该 collation 支持德语 DIN-1 排序(也称为字典顺序):
ß = ss
如果 utf8mb4_unicode_ci
的排序不适合某种语言,MySQL 将实现语言特定的 Unicode collation。例如,utf8mb4_unicode_ci
对德语字典顺序和法语工作得很好,因此不需要创建特殊的 utf8mb4
collation。
utf8mb4_general_ci
也适用于德语和法语,除了 ß
等于 s
,而不是等于 ss
。如果您的应用程序接受这种情况,您应该使用 utf8mb4_general_ci
,因为它更快。如果这不可接受(例如,如果您需要德语字典顺序),请使用 utf8mb4_unicode_ci
,因为它更准确。
如果您需要德语 DIN-2(电话簿)顺序,请使用 utf8mb4_german2_ci
collation,该 collation 将以下字符集视为相等:
Ä = Æ = AE
Ö = Œ = OE
Ü = UE
ß = ss
utf8mb4_german2_ci
类似于 latin1_german2_ci
,但后者不将 Æ
视为等于 AE
或 Œ
视为等于 OE
。由于 utf8mb4_general_ci
足以满足德语字典顺序,因此没有对应的 utf8mb4_german_ci
。
字符的排序权重是根据以下方式确定的:
-
对于所有 Unicode collations 除了
_bin
(二进制)collations,MySQL 都会执行表查找以找到字符的排序权重。 -
对于
_bin
collations 除了utf8mb4_0900_bin
,权重基于代码点,可能添加了前导零字节。 -
对于
utf8mb4_0900_bin
,权重是utf8mb4
编码字节。排序顺序与utf8mb4_bin
相同,但速度更快。
可以使用 WEIGHT_STRING()
函数显示比较权重。(见 第 14.8 节,“字符串函数和操作符”。)如果排序规则使用权重查找表,但字符不在表中(例如,因为它是一个 “新” 字符),那么比较权重的确定将变得更加复杂:
-
对于 BMP 字符在通用排序规则中 (
),权重是代码点。xxx
_general_ci -
对于 BMP 字符在 UCA 排序规则中(例如,
和语言特定排序规则),以下算法适用:xxx
_unicode_ciif (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_ci0x0dc6
,而 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
0E33
和0E4A
是 UCA 4.0.0 中的主要权重。FFFD
是 KAB 和 KISH 的权重。所有补充字符彼此相等的规则不是最优的,但不太可能引起问题。这些字符非常罕见,因此很少有多字符字符串完全由补充字符组成。在日本,因为补充字符是罕见的汉字 ideographs,典型用户并不关心它们的顺序。 如果您真的想按 MySQL 规则和第二arily 按代码点值排序,它很容易:
ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin
-
基于UCA版本高于4.0.0的补充字符(例如:
),补充字符不一定都具有相同的排序权重。一些具有来自UCAxxx
_unicode_520_ciallkeys.txt
文件的明确权重。其他的权重是根据这个算法计算的:aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;
有一个区别是““按字符的代码值排序”和““按字符的二进制表示排序,””这个区别只出现在 utf16_bin
中,因为surrogates的存在。
假设 utf16_bin
(utf16
的二进制排序)是一个字节-by-byte的比较,而不是““字符-by-character.”如果是这样,那么 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
。但是,他们不按 utf16
值排序,如果我们使用字节-by-byte比较,因为 0xff
> 0xd8
。
所以 MySQL 的 utf16_bin
排序不是““字节-by-byte.” 它是““按代码点.” 当 MySQL 看到 utf16
中的补充字符编码时,它将其转换为字符的代码点值,然后比较。因此,utf8mb4_bin
和 utf16_bin
排序相同。这与 SQL:2008 标准要求的 UCS_BASIC 排序一致:“UCS_BASIC 是一个排序,其中排序完全由字符串中字符的 Unicode 标量值确定。它适用于 UCS 字符repertoire。由于每个字符repertoire都是 UCS 字符repertoire 的子集,因此 UCS_BASIC 排序可能适用于每个字符集。注意 11:字符的 Unicode 标量值是其代码点视为无符号整数。”
如果字符集是 ucs2
,比较是字节-by-byte的,但是 ucs2
字符串不应该包含surrogates,反正。