溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Mysql是怎樣兼容各種字符集的

發(fā)布時(shí)間:2020-05-19 15:12:17 來(lái)源:網(wǎng)絡(luò) 閱讀:331 作者:三月 欄目:編程語(yǔ)言

下面一起來(lái)了解下Mysql是怎樣兼容各種字符集的,相信大家看完肯定會(huì)受益匪淺,文字在精不在多,希望Mysql是怎樣兼容各種字符集的這篇短內(nèi)容是你想要的。

過(guò)一下字符集

Unicode 作為現(xiàn)在通用的字符集,通常采用兩個(gè)字節(jié)表示一個(gè)字符,帶來(lái)的副作用就是,原本采用 ASCII 字符集只需要一個(gè)字節(jié)的,卻變成了 2 個(gè)字節(jié),造成了空間浪費(fèi),而 UTF-8 編碼規(guī)則,將 Unicode 編碼成 1~4 個(gè)字節(jié),ASCII 字符集繼續(xù)保持了 1 個(gè)字節(jié)空間,而中文編碼成了三個(gè)字節(jié),如下圖。

Mysql是怎樣兼容各種字符集的

對(duì)存儲(chǔ)帶來(lái)了什么影響

先說(shuō)明下 Mysql 中存在兩種字符集 utf8 和 utf8mb4,以下例子均以 Mysql 的 utf8(1~3個(gè)字節(jié))為例。

采用 utf8 編碼的確很不錯(cuò),但是也帶來(lái)了一個(gè)問(wèn)題,例如我在 Mysql 中定義了一個(gè)定長(zhǎng)字符類(lèi)型 char(5):

nametypelength
titlechar5

所謂定長(zhǎng)字符類(lèi)型代表我要給 title 分配 5 個(gè)字符大小的空間,可是 utf8 每個(gè)字符可能是 1~3 個(gè)字節(jié),我該分配多少空間合適呢?

理論上為了兼容,最好應(yīng)該采用 utf8 的最大 3 個(gè)字節(jié)進(jìn)行分配,也就是 5*3 = 15 個(gè)字節(jié)的空間,這樣我不管以后怎么修改這個(gè)字段的值,空間都能完美滿(mǎn)足需求,但是如果此時(shí)存儲(chǔ)的都是英文,比如 5 個(gè) I,就會(huì)足足浪費(fèi) 10 個(gè)字節(jié)的空間,如果這列以后都存英文,那么至少會(huì)浪費(fèi) 2/3 的空間。

Mysql是怎樣兼容各種字符集的

在 Mysql5.0 之前的行格式設(shè)計(jì)中,也就是 Redundant 行格式,char(5) 的確就如上面設(shè)計(jì)占用了 15 個(gè)字節(jié)空間,隨著版本的迭代,后續(xù)出來(lái)的 Compact,Dynamic,Compressed 行格式都采用了另一種設(shè)計(jì)。

在對(duì)于 utf8 這類(lèi)變長(zhǎng)編碼規(guī)則的 char 類(lèi)型,采用同 varchar 類(lèi)型一樣的存儲(chǔ)方式,就是在前面用一個(gè)或兩個(gè)字節(jié)表示該列實(shí)際占用的字節(jié)數(shù),對(duì)應(yīng)到上圖存儲(chǔ) 5 個(gè) I 的例子,就是 05(實(shí)際占用字節(jié)數(shù))+5 個(gè)存儲(chǔ) I 的字節(jié)空間。

當(dāng)然,更極端點(diǎn),我只存儲(chǔ)了一個(gè) I,這時(shí) char(5) 就會(huì)使用 utf8 的最小字節(jié)數(shù) 1*5(char定義的字符長(zhǎng)度)的大小作為最小分配空間,空出的 4 個(gè)字節(jié)空間用空格字符填充,也就是說(shuō),對(duì)于 title 來(lái)說(shuō),至少會(huì)分配 5 個(gè)字節(jié)空間。

Mysql是怎樣兼容各種字符集的

上面只是對(duì)列為 char(5) 的數(shù)據(jù)進(jìn)行說(shuō)明,在真實(shí)數(shù)據(jù)庫(kù)表中,會(huì)存在多列 varchar 或 char 類(lèi)型,由上可知變長(zhǎng)編碼規(guī)則的 char 也是按 varchar 處理的,所以這些列的實(shí)際占用字節(jié)數(shù)都會(huì)逆序存放在行格式首部,被稱(chēng)為變長(zhǎng)字段長(zhǎng)度列表,而每列的數(shù)據(jù),則是順序存放在列值中,如下圖,至于變長(zhǎng)字段長(zhǎng)度列表和 Null 值列表為什么是逆序的,大家有興趣可以去想想。

Mysql是怎樣兼容各種字符集的

帶來(lái)的更新問(wèn)題

采用上面的設(shè)計(jì),在大部分情況下能省下了很多空間,也提升了查詢(xún)效率,但是也帶來(lái)了另一個(gè)問(wèn)題,那就是更新,用兩個(gè)例子說(shuō)明下:

將 title 從 1個(gè) I 更新為 5 個(gè) I

這個(gè)很好處理,因?yàn)?char(5) 最低會(huì)分配 5 個(gè)字節(jié)空間,更改為 5 個(gè) I,不會(huì)產(chǎn)生任何影響,直接更新就好。

將 title 從 5 個(gè) I 更改為 5 個(gè)我

5 個(gè)我 = 5 * 3 = 15 個(gè)字節(jié)空間,而實(shí)際記錄只有 5 個(gè)字節(jié)空間,空間不足以支撐更新,這時(shí)候的更新只能將原數(shù)據(jù)的整行記錄刪除,然后再新分配合適空間供其使用,看似也沒(méi)什么,但是這種刪 + 增實(shí)際會(huì)對(duì)頁(yè)產(chǎn)生很多變更,這么多變更又要保證它的事務(wù)性,也就是記錄 redo , undo 日志,還是挺復(fù)雜和麻煩的。

Mysql的字符集轉(zhuǎn)換機(jī)制

一個(gè)請(qǐng)求從客戶(hù)端到 Mysql云服務(wù)器,再到表,再返回給客戶(hù)端,中間是經(jīng)過(guò)多層字符集轉(zhuǎn)換的,主要包括下面4層:

轉(zhuǎn)換配置說(shuō)明例子
character_set_client客戶(hù)端請(qǐng)求所用字符集utf8
character_set_connection服務(wù)器將 character_set_client 轉(zhuǎn)碼為 character_set_connectiongbk
表、列字符集將 character_set_connection 轉(zhuǎn)碼為表、列定義的字符集,反之亦然ascii
character_set_results返回客戶(hù)端字符集utf8

假設(shè)我們查詢(xún) title 列,并且 Mysql 各種變量以及列字符集采用上面表格的例子,那么轉(zhuǎn)換如下:

select title from title_demo where title = 'IIIIII'

Mysql是怎樣兼容各種字符集的

當(dāng)然,實(shí)際開(kāi)發(fā)中,我們都會(huì)統(tǒng)一均采用 utf8 ,這樣就有效避免了各層字符集轉(zhuǎn)換帶來(lái)的性能影響。

看完Mysql是怎樣兼容各種字符集的這篇文章后,很多讀者朋友肯定會(huì)想要了解更多的相關(guān)內(nèi)容,如需獲取更多的行業(yè)信息,可以關(guān)注我們的行業(yè)資訊欄目。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI