前言:
在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比較規則
最后以思維導圖的方式總結下本文的主要內容: