12.10.1 Unicode 字符集
本节描述了 Unicode 字符集的可用排序规则及其区别性质。关于 Unicode 的一般信息,请参见第 12.9 节,“Unicode 支持”。
MySQL 支持多种 Unicode 字符集:
-
utf8mb4
:使用一个到四个字节表示 Unicode 字符集的 UTF-8 编码。 -
utf8mb3
:使用一个到三个字节表示 Unicode 字符集的 UTF-8 编码。该字符集已弃用,建议使用utf8mb4
。 -
utf8
:utf8mb3
的别名。请使用utf8mb4
。Noteutf8
将来版本中将变为utf8mb4
的别名。 -
ucs2
: Unicode 字符集的 UCS-2 编码,使用两个字节表示每个字符。已弃用,预计在未来 MySQL 版本中将被删除。 -
utf16
: Unicode 字符集的 UTF-16 编码,使用两个或四个字节表示每个字符。与ucs2
类似,但支持补充字符。 -
utf16le
: Unicode 字符集的 UTF-16LE 编码。与utf16
类似,但使用小端序。 -
utf32
: Unicode 字符集的 UTF-32 编码,使用四个字节表示每个字符。
警告:utf8mb3
字符集已弃用,未来 MySQL 版本中将被删除。请使用 utf8mb4
替代。utf8
目前是 utf8mb3
的别名,但现在已经被弃用,预计将来会变成 utf8mb4
的别名。utf8mb3
也在信息架构表的列和 SQL 语句的输出中显示为 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
。这两个二进制排序的顺序相同,但通过 pad 属性和权重特征进行区分。见排序pad属性,和字符权重。
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 的字符只有在参数排序规则使用高于 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
排序规则的属性是 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 中定义。 -
该排序规则适用于范围 [U+0, U+10FFFF] 的所有字符。
-
如果排序规则不是语言特定的,它将按照默认顺序(以下描述)对所有字符进行排序。如果排序规则是语言特定的,它将根据语言特定规则正确地对语言字符进行排序,对于不在语言中的字符使用默认顺序。
-
默认情况下,排序规则根据 DUCET 表(Default Unicode Collation Element Table)中分配的权重值对字符进行排序。对于没有在 DUCET 表中的字符,它们将使用隐式权重值,这个权重值根据 UCA 构建。
-
对于非语言特定的排序规则,合约序列中的字符被视为单独的字符。对于语言特定的排序规则,合约可能会改变字符排序顺序。
包含locale代码或语言名称的排序规则名称是语言特定的排序规则。Unicode 字符集可能包括这些语言的排序规则。
表 12.3 Unicode 排序语言指定符
Language | Language Specifier |
---|---|
波斯尼亚语 | bs |
保加利亚语 | bg |
中文 | zh |
古典拉丁语 | la 或 roman |
克罗地亚语 | 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 这两个保加利亚编码。
克罗地亚编码是为这些克罗地亚字母而设计的:Č
,Ć
,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-tilde) 在 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
两个排序规则之间的一个差异是:
ß = 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_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 规则和次要按代码点值排序,可以这样:
ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin
-
对于基于 UCA 版本高于 4.0.0 的补充字符(例如,
),补充字符不一定都具有相同的排序权重。一些字符从 UCA 文件xxx
_unicode_520_ciallkeys.txt
中获取明确的权重,其他字符则根据以下算法计算权重:aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;
存在“按字符代码值排序”和“按字符二进制表示排序”的差异,这种差异只在 utf16_bin
中出现,因为有 surrogate。
假设 utf16_bin
(utf16
的二进制排序)是“字节-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_bin
和 utf16_bin
排序是一致的。这与 SQL:2008 标准对 UCS_BASIC 排序的要求一致:“UCS_BASIC 是一个在字符串排序中由字符 Unicode 字符值确定的排序。它适用于 UCS 字符库。由于每个字符库都是 UCS 库的子集,UCS_BASIC 排序可能适用于每个字符集。注意 11:字符的 Unicode 字符值是其代码点视为无符号整数.”
如果字符集是 ucs2
,比较是字节-by 字节,但是 ucs2
字符串不应该包含代理项。
The
排序保留了原始 xxx
_general_mysql500_ci
排序的前 5.1.24 版本,并允许在 MySQL 5.1.24 之前的表创建升级(Bug #27877)。xxx
_general_ci