本篇文章給大家?guī)?lái)了關(guān)于mysql中字符集比較的相關(guān)知識(shí),其中包括了MySQL中支持的字符集和排序規(guī)則,希望對(duì)大家有幫助。
字符集和比較規(guī)則簡(jiǎn)介
字符集簡(jiǎn)介
我們知道在計(jì)算機(jī)中只能存儲(chǔ)二進(jìn)制數(shù)據(jù),那該怎么存儲(chǔ)字符串呢?當(dāng)然是建立字符與二進(jìn)制數(shù)據(jù)的映射關(guān)系了,建立這個(gè)關(guān)系最起碼要搞清楚兩件事兒:
-
你要把哪些字符映射成二進(jìn)制數(shù)據(jù)?
也就是界定清楚字符范圍。
-
怎么映射?
將一個(gè)字符映射成一個(gè)二進(jìn)制數(shù)據(jù)的過(guò)程也叫做
編碼
,將一個(gè)二進(jìn)制數(shù)據(jù)映射到一個(gè)字符的過(guò)程叫做解碼
。
人們抽象出一個(gè)字符集
的概念來(lái)描述某個(gè)字符范圍的編碼規(guī)則。比方說(shuō)我們來(lái)自定義一個(gè)名稱(chēng)為xiaohaizi
的字符集,它包含的字符范圍和編碼規(guī)則如下:
-
包含字符
'a'
、'b'
、'A'
、'B'
。 -
編碼規(guī)則如下:
采用1個(gè)字節(jié)編碼一個(gè)字符的形式,字符和字節(jié)的映射關(guān)系如下:
'a' -> 00000001 (十六進(jìn)制:0x01) 'b' -> 00000010 (十六進(jìn)制:0x02) 'A' -> 00000011 (十六進(jìn)制:0x03) 'B' -> 00000100 (十六進(jìn)制:0x04)
有了xiaohaizi
字符集,我們就可以用二進(jìn)制形式表示一些字符串了,下邊是一些字符串用xiaohaizi
字符集編碼后的二進(jìn)制表示:
'bA' -> 0000001000000011 (十六進(jìn)制:0x0203) 'baB' -> 000000100000000100000100 (十六進(jìn)制:0x020104) 'cd' -> 無(wú)法表示,字符集xiaohaizi不包含字符'c'和'd'
比較規(guī)則簡(jiǎn)介
在我們確定了xiaohaizi
字符集表示字符的范圍以及編碼規(guī)則后,怎么比較兩個(gè)字符的大小呢?最容易想到的就是直接比較這兩個(gè)字符對(duì)應(yīng)的二進(jìn)制編碼的大小,比方說(shuō)字符'a'
的編碼為0x01
,字符'b'
的編碼為0x02
,所以'a'
小于'b'
,這種簡(jiǎn)單的比較規(guī)則也可以被稱(chēng)為二進(jìn)制比較規(guī)則,英文名為binary collation
。
二進(jìn)制比較規(guī)則是簡(jiǎn)單,但有時(shí)候并不符合現(xiàn)實(shí)需求,比如在很多場(chǎng)合對(duì)于英文字符我們都是不區(qū)分大小寫(xiě)的,也就是說(shuō)'a'
和'A'
是相等的,在這種場(chǎng)合下就不能簡(jiǎn)單粗暴的使用二進(jìn)制比較規(guī)則了,這時(shí)候我們可以這樣指定比較規(guī)則:
- 將兩個(gè)大小寫(xiě)不同的字符全都轉(zhuǎn)為大寫(xiě)或者小寫(xiě)。
- 再比較這兩個(gè)字符對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)。
這是一種稍微復(fù)雜一點(diǎn)點(diǎn)的比較規(guī)則,但是實(shí)際生活中的字符不止英文字符一種,比如我們的漢字有幾萬(wàn)之多,對(duì)于某一種字符集來(lái)說(shuō),比較兩個(gè)字符大小的規(guī)則可以制定出很多種,也就是說(shuō)同一種字符集可以有多種比較規(guī)則,我們稍后就要介紹各種現(xiàn)實(shí)生活中用的字符集以及它們的一些比較規(guī)則。
一些重要的字符集
不幸的是,這個(gè)世界太大了,不同的人制定出了好多種字符集
,它們表示的字符范圍和用到的編碼規(guī)則可能都不一樣。我們看一下一些常用字符集的情況:
-
ASCII
字符集共收錄128個(gè)字符,包括空格、標(biāo)點(diǎn)符號(hào)、數(shù)字、大小寫(xiě)字母和一些不可見(jiàn)字符。由于總共才128個(gè)字符,所以可以使用1個(gè)字節(jié)來(lái)進(jìn)行編碼,我們看一些字符的編碼方式:
'L' -> 01001100(十六進(jìn)制:0x4C,十進(jìn)制:76) 'M' -> 01001101(十六進(jìn)制:0x4D,十進(jìn)制:77)
-
ISO 8859-1
字符集共收錄256個(gè)字符,是在
ASCII
字符集的基礎(chǔ)上又?jǐn)U充了128個(gè)西歐常用字符(包括德法兩國(guó)的字母),也可以使用1個(gè)字節(jié)來(lái)進(jìn)行編碼。這個(gè)字符集也有一個(gè)別名latin1
。 -
GB2312
字符集收錄了漢字以及拉丁字母、希臘字母、日文平假名及片假名字母、俄語(yǔ)西里爾字母。其中收錄漢字6763個(gè),其他文字符號(hào)682個(gè)。同時(shí)這種字符集又兼容
ASCII
字符集,所以在編碼方式上顯得有些奇怪:- 如果該字符在
ASCII
字符集中,則采用1字節(jié)編碼。 - 否則采用2字節(jié)編碼。
這種表示一個(gè)字符需要的字節(jié)數(shù)可能不同的編碼方式稱(chēng)為
變長(zhǎng)編碼方式
。比方說(shuō)字符串'愛(ài)u'
,其中'愛(ài)'
需要用2個(gè)字節(jié)進(jìn)行編碼,編碼后的十六進(jìn)制表示為0xB0AE
,'u'
需要用1個(gè)字節(jié)進(jìn)行編碼,編碼后的十六進(jìn)制表示為0x75
,所以拼合起來(lái)就是0xB0AE75
。小貼士: 我們?cè)趺磪^(qū)分某個(gè)字節(jié)代表一個(gè)單獨(dú)的字符還是代表某個(gè)字符的一部分呢?別忘了`ASCII`字符集只收錄128個(gè)字符,使用0~127就可以表示全部字符,所以如果某個(gè)字節(jié)是在0~127之內(nèi)的,就意味著一個(gè)字節(jié)代表一個(gè)單獨(dú)的字符,否則就是兩個(gè)字節(jié)代表一個(gè)單獨(dú)的字符。
- 如果該字符在
-
GBK
字符集GBK
字符集只是在收錄字符范圍上對(duì)GB2312
字符集作了擴(kuò)充,編碼方式上兼容GB2312
。 -
utf8
字符集收錄地球上能想到的所有字符,而且還在不斷擴(kuò)充。這種字符集兼容
ASCII
字符集,采用變長(zhǎng)編碼方式,編碼一個(gè)字符需要使用1~4個(gè)字節(jié),比方說(shuō)這樣:'L' -> 01001100(十六進(jìn)制:0x4C) '啊' -> 111001011001010110001010(十六進(jìn)制:0xE5958A)
小貼士: 其實(shí)準(zhǔn)確的說(shuō),utf8只是Unicode字符集的一種編碼方案,Unicode字符集可以采用utf8、utf16、utf32這幾種編碼方案,utf8使用1~4個(gè)字節(jié)編碼一個(gè)字符,utf16使用2個(gè)或4個(gè)字節(jié)編碼一個(gè)字符,utf32使用4個(gè)字節(jié)編碼一個(gè)字符。更詳細(xì)的Unicode和其編碼方案的知識(shí)不是本書(shū)的重點(diǎn),大家上網(wǎng)查查哈~ MySQL中并不區(qū)分字符集和編碼方案的概念,所以后邊嘮叨的時(shí)候把utf8、utf16、utf32都當(dāng)作一種字符集對(duì)待。
對(duì)于同一個(gè)字符,不同字符集也可能有不同的編碼方式。比如對(duì)于漢字'我'
來(lái)說(shuō),ASCII
字符集中根本沒(méi)有收錄這個(gè)字符,utf8
和gb2312
字符集對(duì)漢字我
的編碼方式如下:
utf8編碼:111001101000100010010001 (3個(gè)字節(jié),十六進(jìn)制表示是:0xE68891) gb2312編碼:1011000010101110 (2個(gè)字節(jié),十六進(jìn)制表示是:0xB0AE)
MySQL中支持的字符集和排序規(guī)則
MySQL中的utf8和utf8mb4
我們上邊說(shuō)utf8
字符集表示一個(gè)字符需要使用1~4個(gè)字節(jié),但是我們常用的一些字符使用1~3個(gè)字節(jié)就可以表示了。而在MySQL
中字符集表示一個(gè)字符所用最大字節(jié)長(zhǎng)度在某些方面會(huì)影響系統(tǒng)的存儲(chǔ)和性能,所以設(shè)計(jì)MySQL
的大叔偷偷的定義了兩個(gè)概念:
-
utf8mb3
:閹割過(guò)的utf8
字符集,只使用1~3個(gè)字節(jié)表示字符。 -
utf8mb4
:正宗的utf8
字符集,使用1~4個(gè)字節(jié)表示字符。
有一點(diǎn)需要大家十分的注意,在MySQL
中utf8
是utf8mb3
的別名,所以之后在MySQL
中提到utf8
就意味著使用1~3個(gè)字節(jié)來(lái)表示一個(gè)字符,如果大家有使用4字節(jié)編碼一個(gè)字符的情況,比如存儲(chǔ)一些emoji表情啥的,那請(qǐng)使用utf8mb4
。
字符集的查看
MySQL
支持好多好多種字符集,查看當(dāng)前MySQL
中支持的字符集可以用下邊這個(gè)語(yǔ)句:
SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式];
其中CHARACTER SET
和CHARSET
是同義詞,用任意一個(gè)都可以。我們查詢(xún)一下(支持的字符集太多了,我們省略了一些):
mysql> SHOW CHARSET; +----------+---------------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | +----------+---------------------------------+---------------------+--------+ | big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 | ... | latin1 | cp1252 West European | latin1_swedish_ci | 1 | | latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 | ... | ascii | US ASCII | ascii_general_ci | 1 | ... | gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 | ... | gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 | | latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 | ... | utf8 | UTF-8 Unicode | utf8_general_ci | 3 | | ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 | ... | latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 | | utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 | | utf16 | UTF-16 Unicode | utf16_general_ci | 4 | | utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 | ... | utf32 | UTF-32 Unicode | utf32_general_ci | 4 | | binary | Binary pseudo charset | binary | 1 | ... | gb18030 | China National Standard GB18030 | gb18030_chinese_ci | 4 | +----------+---------------------------------+---------------------+--------+ 41 rows in set (0.01 sec)
可以看到,我使用的這個(gè)MySQL
版本一共支持41
種字符集,其中的Default collation
列表示這種字符集中一種默認(rèn)的比較規(guī)則
。大家注意返回結(jié)果中的最后一列Maxlen
,它代表該種字符集表示一個(gè)字符最多需要幾個(gè)字節(jié)。為了讓大家的印象更深刻,我把幾個(gè)常用到的字符集的Maxlen
列摘抄下來(lái),大家務(wù)必記住:
字符集名稱(chēng) | Maxlen |
---|---|
ascii |
1 |
latin1 |
1 |
gb2312 |
2 |
gbk |
2 |
utf8 |
3 |
utf8mb4 |
4 |
比較規(guī)則的查看
查看MySQL
中支持的比較規(guī)則的命令如下:
SHOW COLLATION [LIKE 匹配的模式];
我們前邊說(shuō)過(guò)一種字符集可能對(duì)應(yīng)著若干種比較規(guī)則,MySQL
支持的字符集就已經(jīng)非常多了,所以支持的比較規(guī)則