10.10.1 Unicode 字符集
本节介绍可用于 Unicode 字符集的排序规则及其区分属性。有关 Unicode 的常规信息,请参见第 10.9 节“ Unicode 支持”。
MySQL 支持多种 Unicode 字符集:
-
utf8mb4
:Unicode 字符集的 UTF-8 编码,每个字符使用 1-4 个字节。 -
utf8mb3
:Unicode 字符集的 UTF-8 编码,每个字符使用一到三个字节。 -
utf8
:utf8mb3
的别名。 -
ucs2
:Unicode 字符集的 UCS-2 编码,每个字符使用两个字节。 -
utf16
:Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2
,但扩展了辅助字符。 -
utf16le
:Unicode 字符集的 UTF-16LE 编码。像utf16
,但是小端而不是大端。 -
utf32
:Unicode 字符集的 UTF-32 编码,每个字符使用四个字节。
utf8mb4
,utf16
,utf16le
和utf32
支持 BMP 之外的基本多语言平面(BMP)字符和补充字符。 utf8
和ucs2
仅支持 BMP 字符。
大多数 Unicode 字符集具有常规排序规则(名称中用_general
table 示或没有语言说明符),二进制排序规则(名称中用_bin
table 示)以及几种特定于语言的排序规则(由语言说明符 table 示)。例如,对于utf8mb4
,utf8mb4_general_ci
和utf8mb4_bin
是其常规归类和二进制归类,而utf8mb4_danish_ci
是其特定于语言的归类之一。
utf16le
的排序规则支持是有限的。唯一可用的排序规则是utf16le_general_ci
和utf16le_bin
。这些类似于utf16_general_ci
和utf16_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.txt。 xxx_unicode_ci
归类仅部分支持 Unicode 归类算法。不支持某些字符,并且不完全支持组合标记。这主要影响越南语,约鲁巴语和一些较小的语言,例如 Navajo。在字符串比较中,组合字符被认为与用单个 unicode 字符编写的相同字符不同,并且两个字符被认为具有不同的长度(例如,由CHAR_LENGTH()函数返回或在结果集元数据中)。
基于高于 4.0.0 的 UCA 版本的 Unicode 归类在归类名称中包含该版本。因此,utf8_unicode_520_ci
基于 UCA 5.2.0 权重键(http://www.unicode.org/Public/UCA/5.2.0/allkeys.txt)。
LOWER()和UPPER()函数根据其参数的排序规则执行大小写折叠。仅当参数归类使用足够高的 UCA 版本时,这些函数才能转换仅在 Unicode 版本高于 4.0.0 中具有大写和小写版本的字符。
Language-Specific Collations
如果仅基于 Unicode 排序规则算法(UCA)的排序不适用于某种语言,则 MySQL 将实现特定于语言的 Unicode 排序规则。特定于语言的归类基于 UCA,并带有其他语言定制规则。此类规则的示例将在本节后面介绍。对于有关特定语言 Sequences 的问题,unicode.org在http://www.unicode.org/cldr/charts/30/collation/index.html提供了通用语言环境数据存储库(CLDR)整理 table。
下 table 中显示的语言名称 table 示特定于语言的排序规则。 Unicode 字符集可以包括一种或多种这些语言的排序规则。
table10.3 Unicode 归类语言说明符
Language | Language Specifier |
---|---|
Classical Latin | roman |
Croatian | croatian |
Czech | czech |
Danish | danish |
Esperanto | esperanto |
Estonian | estonian |
德国电话簿订单 | german2 |
Hungarian | hungarian |
Icelandic | icelandic |
Latvian | latvian |
Lithuanian | lithuanian |
Persian | persian |
Polish | polish |
Romanian | romanian |
Sinhala | sinhala |
Slovak | slovak |
Slovenian | slovenian |
Modern Spanish | spanish |
Traditional Spanish | spanish2 |
Swedish | swedish |
Turkish | turkish |
Vietnamese | vietnamese |
针对以下克罗地亚字母量身定制了克罗地亚排序规则:Č
,Ć
,Dž
,Đ
,Lj
,Nj
,Š
,Ž
。
丹麦归类也可用于挪威语。
对于古典拉丁归类,I
和J
比较相等,而U
和V
比较相等。
西班牙语归类可用于现代和传统西班牙语。对于两者而言,ñ
(n-tilde)是n
和o
之间的单独字母。另外,对于传统西班牙语,ch
是c
和d
之间的单独字母,而ll
是l
和m
之间的单独字母。
传统的西班牙归类也可以用于阿斯图里亚斯语和加利西亚语。
瑞典归类包括瑞典规则。例如,在瑞典语中,以下关系成立,德语或法语使用者则不会期望这种关系:
Ü = Y < Ö
_general_ci 与_unicode_ci 归类
对于任何 Unicode 字符集,使用xxx_general_ci
归类执行的操作都比使用xxx_unicode_ci
归类进行的操作要快。例如,对utf8_general_ci
归类的比较比对utf8_unicode_ci
的比较更快,但正确性稍差。原因是utf8_unicode_ci
支持扩展等 Map;也就是说,一个字符与其他字符的组合相等时。例如,在德语和某些其他语言中,ß
等于ss
。 utf8_unicode_ci
还支持收缩和可忽略字符。 utf8_general_ci
是不支持扩展,收缩或可忽略字符的传统排序规则。它只能在字符之间进行一对一比较。
为了进一步说明,在utf8_general_ci
和utf8_unicode_ci
中都具有以下相等性(有关比较或搜索中的效果,请参见第 10.8.6 节“排序规则效果的示例”):
Ä = A
Ö = O
Ü = U
归类之间的不同之处在于utf8_general_ci
是正确的:
ß = s
而对于utf8_unicode_ci
,这是正确的,它支持德语 DIN-1 排序(也称为字典 Sequences):
ß = ss
如果使用utf8_unicode_ci
的排序不适用于某种语言,则 MySQL 将实现utf8
语言特定的排序规则。例如,utf8_unicode_ci
适用于德语字典 Sequences 和法语,因此无需创建特殊的utf8
归类。
utf8_general_ci
对德语和法语都令人满意,除了ß
等于s
而不是ss
。如果这对于您的应用程序是可接受的,则应使用utf8_general_ci
,因为它速度更快。如果这是不可接受的(例如,如果您需要德语词典 Sequences),请使用utf8_unicode_ci
,因为它更准确。
如果您需要 Order 德国 DIN-2(电话簿),请使用utf8_german2_ci
归类,它将以下几组字符进行比较:
Ä = Æ = AE
Ö = Œ = OE
Ü = UE
ß = ss
utf8_german2_ci
与latin1_german2_ci
类似,但后者不比较Æ
等于AE
或Œ
等于OE
。因为utf8_general_ci
就足够了,所以对于德国词典 Sequences,没有utf8_german_ci
对应于latin1_german_ci
。
字符整理权重
角色的归类权重确定如下:
-
对于除
_bin
(二进制)归类外的所有 Unicode 归类,MySQL 执行 table 查找以查找字符的归类权重。 -
对于
_bin
归类,权重基于代码点,可能添加了前导零字节。
可以使用WEIGHT_STRING()功能显示整理权重。 (请参阅第 12.7 节“字符串函数和运算符”。)如果排序规则使用权重查找 table,但是 table 中没有字符(例如,因为它是“新”字符),则排序权重确定变得更加复杂:
-
对于一般归类(
xxx_general_ci
)中的 BMP 字符,权重是代码点。 -
对于 UCA 归类中的 BMP 字符(例如
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 |
+----------------------------------------------------------+
因此,在所有 UCA 4.0.0 归类中,U+04cf CYRILLIC SMALL LETTER PALOCHKA
大于U+04c0 CYRILLIC LETTER PALOCHKA
。使用 UCA 5.2.0 归类,所有 palochka 都可以排序。
- 对于一般归类中的补充字符,权重是
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
.)
一个带有楔形 Literals 和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 的权重。
所有补充字符都相等的规则不是最佳的,但是不会引起麻烦。这些字符非常少见,因此由多字符组成的字符串完全由补充字符组成非常罕见。在日本,由于辅助字符是晦涩的汉字 table 意 Literals,因此一般用户根本不在乎它们的 Sequences。如果您确实希望按 MySQL 规则对行进行排序,然后再按代码点值对行进行排序,则很简单:
ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin
- 对于基于高于 4.0.0 的 UCA 版本的补充字符(例如
xxx_unicode_520_ci
),补充字符不一定都具有相同的整理重量。有些具有来自 UCAallkeys.txt
文件的明确权重。其他人具有根据此算法计算的权重:
aaaa= base + (code >> 15);
bbbb= (code & 0x7FFF) | 0x8000;
在“按字符的代码值排序”和“按字符的二进制 table 示形式排序”之间存在差异,这是由于代理而仅在utf16_bin
上出现的差异。
假设utf16_bin
(utf16
的二进制排序规则)是“逐字节”而不是“逐字符”的二进制比较。如果是这样,则utf16_bin
中的字符 Sequences 将与utf8_bin
中的字符 Sequences 不同。例如,下图显示了两个稀有字符。第一个字符在E000
-FFFF
的范围内,因此它大于替代字符但小于辅助字符。第二个字符是补充字符。
Code point Character utf8 utf16
---------- --------- ---- -----
0FF9D HALFWIDTH KATAKANA LETTER N EF BE 9D FF 9D
10384 UGARITIC LETTER DELTA F0 90 8E 84 D8 00 DF 84
图 table 中的两个字符按代码点值的 Sequences 排列,因为0xff9d
< 0x10384
. And they are in order by utf8
value because 0xef
< 0xf0
. But they are not in order by utf16
value, if we use byte-by-byte comparison, because 0xff
> 0xd8
。
因此,MySQL 的utf16_bin
排序规则不是“逐字节”。这是“按代码点”。当 MySQL 在utf16
中看到辅助字符编码时,它将转换为字符的代码点值,然后进行比较。因此,utf8_bin
和utf16_bin
是相同的 Sequences。这与 UCS_BASIC 排序规则的 SQL:2008 标准要求一致:“ UCS_BASIC 是一种排序规则,其中排序完全由要排序的字符串中字符的 Unicode 标量值确定。它适用于 UCS 字符库。由于每个字符库都是 UCS 库的子集,因此 UCS_BASIC 排序规则可能适用于每个字符集。注 11:字符的 Unicode 标量值是其代码点,被视为无符号整数。”
如果字符集是ucs2
,则比较是逐字节进行的,但是ucs2
字符串无论如何都不应包含替代。
Miscellaneous Information
xxx_general_mysql500_ci
归类保留原始xxx_general_ci
归类在 5.1.24 之前的 Sequences,并允许对在 MySQL 5.1.24 之前创建的 table 进行升级(缺陷号 27877)。