本節說明 Unicode 字元集可用的校對及其區分特性。如需 Unicode 的一般資訊,請參閱第 12.9 節「Unicode 支援」。
MySQL 支援多個 Unicode 字元集
utf8mb4
:使用每個字元一到四個位元組的 Unicode 字元集的 UTF-8 編碼。utf8mb3
:使用每個字元一到三個位元組的 Unicode 字元集的 UTF-8 編碼。此字元集已淘汰;請改用utf8mb4
。utf8
:utf8mb3
的已淘汰別名。請改用utf8mb4
。注意預期在未來版本中,
utf8
將成為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
的別名,但現在已淘汰這種用法,且預期 utf8
後續會成為 utf8mb4
的參照。在資訊綱要表格的欄位中以及 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 版本時,才會轉換僅在 Unicode 4.0.0 以上版本中具有大寫和小寫版本的字元。
基於 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 |
+----------------------------+---------------+
具有 NO PAD
排序規則的非二進位字串值(CHAR
、VARCHAR
和 TEXT
)的比較在尾隨空格方面與其他排序規則不同。例如,'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 校對元素表)中列出的程式碼點,依據表中指定的權重值來排序具有該程式碼點的字元。排序規則會使用其隱含權重值(根據 UCA 建構)排序沒有 DUCET 表中列出的程式碼點的字元。
對於非語言特定的排序規則,縮合序列中的字元會被視為個別字元。對於語言特定的排序規則,縮合可能會變更字元排序順序。
包含下表中所示的地區碼或語言名稱的排序規則名稱是語言特定的排序規則。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
而以下情況對於 utf8mb4_unicode_ci
為真,其支援德語 DIN-1 排序(也稱為字典排序):
ß = 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 西里爾小寫字母 PALOCHKA
(ӏ
)在所有 UCA 4.0.0 校對中,都大於U+04c0 西里爾字母 PALOCHKA
(Ӏ
)。在 UCA 5.2.0 校對中,所有 palochkas 都會排序在一起。對於一般校對中的補充字元,權重是
0xfffd 替換字元
的權重。對於 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
字串不應包含代理對。