本文由horstxu發表php
在mysql中執行show create table <tablename>
指令,能夠看到一張表的建表語句,example以下:html
CREATE TABLE `table1` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `field1` text COLLATE utf8_unicode_ci NOT NULL COMMENT '字段1', `field2` varchar(128) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '字段2', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8_unicode_ci;
大部分字段咱們都能看懂,可是今天要討論的是COLLATE關鍵字。這個值後面對應的utf8_unicode_ci
是什麼意思呢?面試的時候用這個題目考一考DBA,應該能夠難倒一大部分人。mysql
使用phpmyadmin的開發可能會很是眼熟,由於其中的中文表頭已經給出了答案:面試
phpmyadmin截圖算法
所謂utf8_unicode_ci
,實際上是用來排序的規則。對於mysql中那些字符類型的列,如VARCHAR
,CHAR
,TEXT
類型的列,都須要有一個COLLATE
類型來告知mysql如何對該列進行排序和比較。簡而言之,COLLATE會影響到ORDER BY語句的順序,會影響到WHERE條件中大於小於號篩選出來的結果,會影響**DISTINCT**
、**GROUP BY**
、**HAVING**
語句的查詢結果。另外,mysql建索引的時候,若是索引列是字符類型,也會影響索引建立,只不過這種影響咱們感知不到。總之,凡是涉及到字符類型比較或排序的地方,都會和COLLATE有關。sql
COLLATE
一般是和數據編碼(CHARSET
)相關的,通常來講每種CHARSET
都有多種它所支持的COLLATE
,而且每種CHARSET
都指定一種COLLATE
爲默認值。例如Latin1
編碼的默認COLLATE
爲latin1_swedish_ci
,GBK
編碼的默認COLLATE
爲gbk_chinese_ci
,utf8mb4
編碼的默認值爲utf8mb4_general_ci
。app
這裏順便講個題外話,mysql中有utf8
和utf8mb4
兩種編碼,在mysql中請你們忘記**utf8**
,永遠使用**utf8mb4**
。這是mysql的一個遺留問題,mysql中的utf8
最多隻能支持3bytes長度的字符編碼,對於一些須要佔據4bytes的文字,mysql的utf8
就不支持了,要使用utf8mb4
才行。ui
不少COLLATE
都帶有_ci
字樣,這是Case Insensitive的縮寫,即大小寫無關,也就是說"A"和"a"在排序和比較的時候是一視同仁的。selection * from table1 where field1="a"
一樣能夠把field1爲"A"的值選出來。與此同時,對於那些_cs
後綴的COLLATE
,則是Case Sensitive,即大小寫敏感的。編碼
在mysql中使用show collation
指令能夠查看到mysql所支持的全部COLLATE
。以utf8mb4
爲例,該編碼所支持的全部COLLATE
以下圖所示。設計
mysql中和utf8mb4相關的全部COLLATE
圖中咱們能看到不少國家的語言本身的排序規則。在國內比較經常使用的是utf8mb4_general_ci
(默認)、utf8mb4_unicode_ci
、utf8mb4_bin
這三個。咱們來探究一下這三個的區別:
首先utf8mb4_bin
的比較方法其實就是直接將全部字符看做二進制串,而後從最高位往最低位比對。因此很顯然它是區分大小寫的。
而utf8mb4_unicode_ci
和utf8mb4_general_ci
對於中文和英文來講,實際上是沒有任何區別的。對於咱們開發的國內使用的系統來講,隨便選哪一個都行。只是對於某些西方國家的字母來講,utf8mb4_unicode_ci
會比utf8mb4_general_ci
更符合他們的語言習慣一些,general
是mysql一個比較老的標準了。例如,德語字母「ß」
,在utf8mb4_unicode_ci
中是等價於"ss"
兩個字母的(這是符合德國人習慣的作法),而在utf8mb4_general_ci
中,它卻和字母「s」
等價。不過,這兩種編碼的那些微小的區別,對於正常的開發來講,很難感知到。自己咱們也不多直接用文字字段去排序,退一步說,即便這個字母排錯了一兩個,真的能給系統帶來災難性後果麼?從網上找的各類帖子討論來講,更多人推薦使用utf8mb4_unicode_ci
,可是對於使用了默認值的系統,也並無很是排斥,並不認爲有什麼大問題。結論:推薦使用utf8mb4_unicode_ci
,對於已經用了utf8mb4_general_ci
的系統,也沒有必要花時間改造。
另外須要注意的一點是,從mysql 8.0開始,mysql默認的CHARSET
已經再也不是Latin1
了,改成了utf8mb4
(參考連接),而且默認的COLLATE也改成了utf8mb4_0900_ai_ci
。utf8mb4_0900_ai_ci
大致上就是unicode
的進一步細分,0900
指代unicode比較算法的編號( Unicode Collation Algorithm version),ai
表示accent insensitive(發音無關),例如e, è, é, ê 和 ë是一視同仁的。相關參考連接1,相關參考連接2
設置COLLATE
能夠在示例級別、庫級別、表級別、列級別、以及SQL指定。實例級別的COLLATE
設置就是mysql配置文件或啓動指令中的collation_connection
系統變量。
庫級別設置COLLATE
的語句以下:
CREATE DATABASE <db_name> DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
若是庫級別沒有設置CHARSET
和COLLATE
,則庫級別默認的CHARSET
和COLLATE
使用實例級別的設置。在mysql8.0如下版本中,你若是什麼都不修改,默認的CHARSET
是Latin1
,默認的COLLATE
是latin1_swedish_ci
。從mysql8.0開始,默認的CHARSET
已經改成了utf8mb4
,默認的COLLATE
改成了utf8mb4_0900_ai_ci
。
表級別的COLLATE
設置,則是在CREATE TABLE
的時候加上相關設置語句,例如:
CREATE TABLE ( …… ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
若是表級別沒有設置CHARSET
和COLLATE
,則表級別會繼承庫級別的CHARSET
與COLLATE
。
列級別的設置,則在CREATE TABLE
中聲明列的時候指定,例如
CREATE TABLE ( `field1` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', …… ) ……
若是列級別沒有設置CHARSET
和COLATE
,則列級別會繼承表級別的CHARSET
與COLLATE
。
最後,你也能夠在寫SQL查詢的時候顯示聲明COLLATE
來覆蓋任何庫表列的COLLATE
設置,不太經常使用,瞭解便可:
SELECT DISTINCT field1 COLLATE utf8mb4_general_ci FROM table1; SELECT field1, field2 FROM table1 ORDER BY field1 COLLATE utf8mb4_unicode_ci;
若是全都顯示設置了,那麼優先級順序是 SQL語句 > 列級別設置 > 表級別設置 > 庫級別設置 > 實例級別設置。也就是說列上所指定的COLLATE
能夠覆蓋表上指定的COLLATE
,表上指定的COLLATE
能夠覆蓋庫級別的COLLATE
。若是沒有指定,則繼承下一級的設置。即列上面沒有指定COLLATE
,則該列的COLLATE
和表上設置的同樣。
以上就是關於mysql的COLLATE
相關知識。不過,在系統設計中,咱們仍是要儘可能避免讓系統嚴重依賴中文字段的排序結果,在mysql的查詢中也應該儘可能避免使用中文作查詢條件。
此文已由做者受權騰訊雲+社區發佈,更多原文請點擊
搜索關注公衆號「雲加社區」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!