本节介绍适用于 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
。目前,utf8
是 utf8mb3
的别名,但现在已弃用此别名,并且 utf8
预计随后将成为对 utf8mb4
的引用。在 Information Schema 表的列中,以及在 SQL SHOW
语句的输出中,utf8mb3
也将显示为 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 按照 http://www.unicode.org/reports/tr10/ 中描述的 Unicode 排序算法 (UCA) 实现
排序规则。该排序规则使用版本 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()
函数返回,或在结果集元数据中)。
基于高于 4.0.0 的 UCA 版本的 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()
函数根据其参数的排序规则执行大小写转换。只有当参数排序规则使用足够高的 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 |
+----------------------------+---------------+
当非二进制字符串值(CHAR
、VARCHAR
和 TEXT
)具有 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.org 在 http://www.unicode.org/cldr/charts/30/collation/index.html 提供了通用语言数据存储库 (CLDR) 排序图表。
例如,非特定语言的 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 中没有定义。排序规则适用于范围 [U+0, U+10FFFF] 中的所有字符。
如果排序规则不是特定语言的,它会按默认顺序(以下描述)对所有字符(包括补充字符)进行排序。如果排序规则是特定语言的,它会根据特定语言的规则对该语言的字符进行正确的排序,并将该语言中未包含的字符按默认顺序排序。
默认情况下,排序规则根据 DUCET 表(默认 Unicode 排序元素表)中列出的代码点的字符进行排序,并根据表中分配的权重值进行排序。排序规则使用其隐式权重值对 DUCET 表中未列出代码点的字符进行排序,该值是根据 UCA 构造的。
对于非特定语言的排序规则,收缩序列中的字符被视为单独的字符。对于特定语言的排序规则,收缩可能会改变字符的排序顺序。
包含以下表格中显示的区域设置代码或语言名称的排序规则名称是特定语言的排序规则。Unicode 字符集可能包含针对这些语言中的一种或多种语言的排序规则。
表 12.3 Unicode 排序语言说明符
语言 | 语言说明符 |
---|---|
波斯尼亚语 | 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 或 slovak |
斯洛文尼亚语 | sl 或 slovenian |
现代西班牙语 | es 或 spanish |
传统西班牙语 | es_trad 或 spanish2 |
瑞典语 | sv 或 swedish |
土耳其语 | tr 或 turkish |
越南语 | vi 或 vietnamese |
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
使用四个。
对于不区分重音的经典拉丁语排序规则, I
和 J
被视为相等,U
和 V
被视为相等。 I
和 J
以及 U
和 V
在基本字母级别被视为相等。换句话说,J
被视为带有重音的 I
,U
被视为带有重音的 V
。
MySQL 为使用西里尔字母书写的蒙古语提供了排序规则,即 utf8mb4_mn_cyrl_0900_ai_ci
和 utf8mb4_mn_cyrl_0900_as_cs
。
西班牙语排序规则适用于现代西班牙语和传统西班牙语。对于两者,ñ
(带波浪线的 n)是 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
分别相同。)
瑞典语排序规则包括瑞典语规则。例如,在瑞典语中,以下关系成立,这与德语或法语使用者预期的不同
Ü = 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 节,“排序规则影响示例”)
Ä = 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 节,“字符串函数和运算符”。)如果排序规则使用权重查找表,但表中不存在某个字符(例如,因为它是一个 “新” 字符),则确定排序权重会变得更加复杂
对于一般排序规则 (
) 中的 BMP 字符,权重是代码点。xxx
_general_ci对于 UCA 排序规则(例如,
和特定语言的排序规则)中的 BMP 字符,以下算法适用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 的权重。所有补充字符彼此相等的规则并非最佳,但预计不会造成麻烦。这些字符非常罕见,因此由补充字符组成的多字符字符串也很罕见。在日本,由于补充字符是晦涩难懂的汉字,因此普通用户并不关心它们的排序方式。如果您确实希望按 MySQL 规则进行排序,并按代码点值进行二次排序,则非常简单。
ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin
对于基于高于 4.0.0 的 UCA 版本的补充字符(例如
),补充字符并不一定都具有相同的排序权重。有些从 UCAxxx
_unicode_520_ciallkeys.txt
文件中获得了明确的权重。其他则根据此算法计算权重。aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;
“按字符代码值排序”和“按字符的二进制表示排序”之间存在差异,这种差异仅在 utf16_bin
中出现,这是由于代理字符造成的。
假设 utf16_bin
(utf16
的二进制排序)是一个二进制比较“逐字节”而不是“逐字符”。如果是这样,则 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_bin
和 utf16_bin
的排序相同。这与 SQL:2008 标准对 UCS_BASIC 排序的要求一致:“UCS_BASIC 是一种排序,其中排序完全由要排序字符串中字符的 Unicode 标量值决定。它适用于 UCS 字符集。由于每个字符集都是 UCS 字符集的子集,因此 UCS_BASIC 排序可能适用于每个字符集。注意 11:字符的 Unicode 标量值是将其代码点视为无符号整数。”
如果字符集为 ucs2
,则比较为逐字节,但 ucs2
字符串不应该包含代理字符。