utf8字符集下的比較規則

前言: 

在MySQL中,比較常用的字符集是utf8和utf8mb4。這兩個字符集是類似的,utf8是utf8mb3的別名,所以之後在MySQL中提到utf8就意味着使用1~3個字節來表示一個字符,如果大家有使用4字節編碼一個字符的情況,比如存儲一些emoji表情啥的,需要使用utf8mb4。其實每個字符集下對應着若干個比較規則(也可以翻譯爲排序規則或校對規則,英文是COLLATE),同一字符集下,使用不同的比較規則會影響字符字段的比較和排序。本文以utf8爲例,介紹下常用的幾個比較規則的不同。

1.utf8下比較規則概覽

我們先查看下utf8字符集下支持的所有比較規則:

mysql> SHOW COLLATION LIKE 'utf8\_%';
+--------------------------+---------+-----+---------+----------+---------+
| Collation                | Charset | Id  | Default | Compiled | Sortlen |
+--------------------------+---------+-----+---------+----------+---------+
| utf8_general_ci          | utf8    |  33 | Yes     | Yes      |       1 |
| utf8_bin                 | utf8    |  83 |         | Yes      |       1 |
| utf8_unicode_ci          | utf8    | 192 |         | Yes      |       8 |
| utf8_icelandic_ci        | utf8    | 193 |         | Yes      |       8 |
| utf8_latvian_ci          | utf8    | 194 |         | Yes      |       8 |
| utf8_romanian_ci         | utf8    | 195 |         | Yes      |       8 |
| utf8_slovenian_ci        | utf8    | 196 |         | Yes      |       8 |
| utf8_polish_ci           | utf8    | 197 |         | Yes      |       8 |
| utf8_estonian_ci         | utf8    | 198 |         | Yes      |       8 |
| utf8_spanish_ci          | utf8    | 199 |         | Yes      |       8 |
| utf8_swedish_ci          | utf8    | 200 |         | Yes      |       8 |
| utf8_turkish_ci          | utf8    | 201 |         | Yes      |       8 |
| utf8_czech_ci            | utf8    | 202 |         | Yes      |       8 |
| utf8_danish_ci           | utf8    | 203 |         | Yes      |       8 |
| utf8_lithuanian_ci       | utf8    | 204 |         | Yes      |       8 |
| utf8_slovak_ci           | utf8    | 205 |         | Yes      |       8 |
| utf8_spanish2_ci         | utf8    | 206 |         | Yes      |       8 |
| utf8_roman_ci            | utf8    | 207 |         | Yes      |       8 |
| utf8_persian_ci          | utf8    | 208 |         | Yes      |       8 |
| utf8_esperanto_ci        | utf8    | 209 |         | Yes      |       8 |
| utf8_hungarian_ci        | utf8    | 210 |         | Yes      |       8 |
| utf8_sinhala_ci          | utf8    | 211 |         | Yes      |       8 |
| utf8_german2_ci          | utf8    | 212 |         | Yes      |       8 |
| utf8_croatian_ci         | utf8    | 213 |         | Yes      |       8 |
| utf8_unicode_520_ci      | utf8    | 214 |         | Yes      |       8 |
| utf8_vietnamese_ci       | utf8    | 215 |         | Yes      |       8 |
| utf8_general_mysql500_ci | utf8    | 223 |         | Yes      |       1 |
+--------------------------+---------+-----+---------+----------+---------+

這些比較規則的命名還挺有規律的,具體規律如下:

  • 比較規則名稱以與其關聯的字符集的名稱開頭。如上圖的查詢結果的比較規則名稱都是以utf8開頭的。
  • 後邊緊跟着該比較規則主要作用於哪種語言,比如utf8_polish_ci表示以波蘭語的規則比較,utf8_spanish_ci是以西班牙語的規則比較,utf8_general_ci是一種通用的比較規則。
  • 名稱後綴意味着該比較規則是否區分語言中的重音、大小寫啥的,具體可以用的值如下:
後綴 英文釋義 描述
_ai accent insensitive 不區分重音
_as accent sensitive 區分重音
_ci case insensitive 不區分大小寫
_cs case sensitive 區分大小寫
_bin binary 以二進制方式比較

比如utf8_general_ci這個比較規則是以ci結尾的,說明不區分大小寫
每種字符集都有一種默認的比較規則,SHOW COLLATION的返回結果中的Default列的值爲YES的就是該字符集的默認比較規則,比方說utf8字符集默認的比較規則就是utf8_general_ci

比較規則可以作用於四個級別,分別是:服務器級別、數據庫級別、表級別、列級別。服務器級別的比較規則由collation_server參數控制,如果創建數據庫、表、列時沒有顯式的指定比較規則,則會繼承上一級的比較規則。下面給出創建及修改庫、表、列的比較規則的示例語句:

# 創建數據庫指定比較規則 修改數據庫的比較規則
CREATE DATABASE 數據庫名
    [[DEFAULT] CHARACTER SET 字符集名稱]
    [[DEFAULT] COLLATE 比較規則名稱];

ALTER DATABASE 數據庫名
    [[DEFAULT] CHARACTER SET 字符集名稱]
    [[DEFAULT] COLLATE 比較規則名稱];

# 創建表時指定比較規則 修改表的比較規則
CREATE TABLE 表名 (列的信息)
    [[DEFAULT] CHARACTER SET 字符集名稱]
    [COLLATE 比較規則名稱]]

ALTER TABLE 表名
    [[DEFAULT] CHARACTER SET 字符集名稱]
    [COLLATE 比較規則名稱]

# 創建時指定列的比較規則 修改列的比較規則
CREATE TABLE 表名(
    列名 字符串類型 [CHARACTER SET 字符集名稱] [COLLATE 比較規則名稱],
    其他列...
);

ALTER TABLE 表名 MODIFY 列名 字符串類型 [CHARACTER SET 字符集名稱] [COLLATE 比較規則名稱];

2.幾種比較規則對比

utf8字符集下默認的比較規則是utf8_general_ci,日常中會用到的有utf8_general_ci,utf8_unicode_ci,utf8_bin三種比較規則,其他比較規則基本很少會用,下面簡單瞭解下這三種比較規則的異同。

首先utf8_bin的比較方法其實就是直接將所有字符看作二進制串,然後從最高位往最低位比對。所以很顯然它是區分大小寫的。而utf8_general_ci和utf8_unicode_ci是不區分大小寫的。

utf8_general_ci和utf8_unicode_ci對中、英文來說沒有實質的差別。utf8_unicode_ci的最主要的特色是支持擴展,即當把一個字母看作與其它字母組合相等時。例如,在德語和一些其它語言中‘ß'等於‘ss'。utf8_general_ci是一個遺留的比較規則,不支持擴展。它僅能夠在字符之間進行逐個比較。這意味着utf8_general_ci比較規則進行的比較速度很快,但是與utf8_unicode_ci相比,比較正確性較差。

下面我們來實踐下三種比較規則的異同:

# 創建表 指定列爲不同的比較規則
mysql> create table utf8_test (
    -> col_general varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci,
    -> col_unicode varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci,
    -> col_bin varchar(20) CHARACTER SET utf8 COLLATE utf8_bin
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 # 插入數據 每行數據各個字段值一樣
 mysql> select * from utf8_test;
+-------------+-------------+---------+
| col_general | col_unicode | col_bin |
+-------------+-------------+---------+
| MySQL       | MySQL       | MySQL   |
| mysql       | mysql       | mysql   |
| A           | A           | A       |
| a           | a           | a       |
| aA          | aA          | aA      |
+-------------+-------------+---------+

# 查詢 驗證utf8_bin比較規則區分大小寫
mysql> select * from utf8_test where col_general='mysql';
+-------------+-------------+---------+
| col_general | col_unicode | col_bin |
+-------------+-------------+---------+
| MySQL       | MySQL       | MySQL   |
| mysql       | mysql       | mysql   |
+-------------+-------------+---------+
mysql> select * from utf8_test where col_unicode='MySQL';
+-------------+-------------+---------+
| col_general | col_unicode | col_bin |
+-------------+-------------+---------+
| MySQL       | MySQL       | MySQL   |
| mysql       | mysql       | mysql   |
+-------------+-------------+---------+
mysql> select * from utf8_test where col_bin='mysql';       
+-------------+-------------+---------+
| col_general | col_unicode | col_bin |
+-------------+-------------+---------+
| mysql       | mysql       | mysql   |
+-------------+-------------+---------+

# 排序 發現不同排序規則對順序有影響
mysql> select * from utf8_test order by col_general;
+-------------+-------------+---------+
| col_general | col_unicode | col_bin |
+-------------+-------------+---------+
| A           | A           | A       |
| a           | a           | a       |
| aA          | aA          | aA      |
| MySQL       | MySQL       | MySQL   |
| mysql       | mysql       | mysql   |
+-------------+-------------+---------+
mysql> select * from utf8_test order by col_bin;
+-------------+-------------+---------+
| col_general | col_unicode | col_bin |
+-------------+-------------+---------+
| A           | A           | A       |
| MySQL       | MySQL       | MySQL   |
| a           | a           | a       |
| aA          | aA          | aA      |
| mysql       | mysql       | mysql   |
+-------------+-------------+---------+

3.關於比較規則的選擇與建議

對於MySQL 5.7版本,一般情況下建議將字符集改爲utf8,比較規則選擇默認的utf8_general_ci。utf8_general_ci相對於utf8_unicode_ci來說校對速度快,但是如果你的應用有德語、法語或者俄語,建議使用utf8_unicode_ci。如果某個表或列字段要求區分大小寫,可以單獨指定該表或字段使用utf8_bin比較規則

最後以思維導圖的方式總結下本文的主要內容:
image.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章