mysql 數據庫 varchar 到底可以存多少數據呢,長文慎入

一、關于UTF-8

UTF-8 Unicode Transformation Format-8bit。是用以解決國際上字符的一種多字節編碼。

它對英文使用8位(即一個字節),中文使用24位(三個字節)來編碼。

UTF-8包含全世界所有國家需要用到的字符,是國際編碼,通用性強。

UTF-8編碼的文字可以在各國支持UTF8字符集額的瀏覽器上顯示。
如果是UTF8編碼,則在外國人的英文IE也能顯示中文,他們無需下載IE的中文語言支持包。

二、關于GBK

GBK 是國家標準GB2312基礎上擴容后兼容GB2312的標準。
GBK的文字編碼是用雙字節來表示的,即不論中、英文字符均使用雙字節來表示,為了區分中文,將其最高位都設定成1。
GBK包含全部中文字符,是國家編碼,通用性比UTF8差,不過UTF8占用的數據庫比GBK大。

三、關于utf8mb4

MySql 5.5 之前,UTF8 編碼只支持1-3個字節,只支持BMP這部分的unicode編碼區,BMP是從哪到哪?
戳這里 基本就是 0000 ~ FFFF 這一區。

從MySQL 5.5 開始,可支持4個字節UTF編碼utf8mb4,一個字符最多能有4字節,所以能支持更多的字符集。

utf8mb4 is a superset of utf8

tf8mb4兼容utf8,且比utf8能表示更多的字符。
至于什么時候用,看你做的什么項目了。。。
在做移動應用時,會遇到IOS用戶在文本的區域輸入emoji表情,如果不做一定處理,就會導致插入數據庫異常。

四、漢字長度與編碼有關

MySql 5.0 以上的版本:

1、一個漢字占多少長度與編碼有關:

  • UTF-8:一個漢字 = 3個字節,英文是一個字節
  • GBK: 一個漢字 = 2個字節,英文是一個字節

2、varchar(n) 表示n個字符,無論漢字和英文,MySql都能存入 n 個字符,僅實際字節長度有所區別。

3、MySQL檢查長度,可用SQL語言

SELECT LENGTH(fieldname) FROM tablename 

五、實際測試

1、首先使用utf8 創建 str_test 表。

CREATE TABLE `str_test` (
    `name_chn` varchar(20) NOT NULL,
    `name_en`  varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=utf8

然后插入值

mysql> insert into  str_test values ('我愛Ruby', 'I Love Ruby!');
Query OK, 1 row affected (0.02 sec)

打開irb

>> "我愛Ruby".size
=> 6
>> "I Love Ruby!".size
=> 12
>>

從MySQL中查詢出來的結果,對比

mysql> select * from str_test;
+------------+--------------+
| name_chn   | name_en      |
+------------+--------------+
| 我愛Ruby   | I Love Ruby! |
+------------+--------------+
1 row in set (0.02 sec)


mysql> select length(name_chn) from str_test;
+------------------+
| length(name_chn) |
+------------------+
|               10 |
+------------------+
1 row in set (0.01 sec)

3[一個漢字一字節] * 2 + 1[一個英文一字節] * 4 = 10


mysql> select length(name_en) from str_test;
+-----------------+
| length(name_en) |
+-----------------+
|              12 |
+-----------------+
1 row in set (0.00 sec)

  10[一個英文一字節] * 1 + 2[空格一字節] * whitespace = 12

2、使用 GBK 做測試

創建表

    CREATE TABLE `str_test` (
    `name_chn` varchar(20) NOT NULL,
    `name_en`  varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=gbk

插入數據,并且測試

mysql> insert into  str_test values ('我愛Ruby', 'I Love Ruby!');
Query OK, 1 row affected (0.00 sec)

mysql> select * from str_test;
+------------+--------------+
| name_chn   | name_en      |
+------------+--------------+
| 我愛Ruby   | I Love Ruby! |
+------------+--------------+
1 row in set (0.01 sec)

GBK 中文是兩個字節,英文是一個字節。

mysql> select length(name_chn) from str_test;
+------------------+
| length(name_chn) |
+------------------+
|                8 |
+------------------+
1 row in set (0.00 sec)

2[中文兩個字節] * 2 + 4[英文一個字節] * 1 = 8

mysql> select length(name_en) from str_test;
+-----------------+
| length(name_en) |
+-----------------+
|              12 |
+-----------------+
1 row in set (0.00 sec)

10[英文一個字節] * 1 + 2[空格一個字節] * whitespace = 12
六、關于varchar 最多能存多少值
  • mysql的記錄行長度是有限制的,不是無限長的,這個長度是64K,即65535個字節,對所有的表都是一樣的。

  • MySQL對于變長類型的字段會有1-2個字節來保存字符長度。

  • 當字符數小于等于255時,MySQL只用1個字節來記錄,因為2的8次方減1只能存到255。

  • 當字符數多余255時,就得用2個字節來存長度了。

  • utf-8狀態下的varchar,最大只能到 (65535 - 2) / 3 = 21844 余 1。

  • gbk狀態下的varchar, 最大只能到 (65535 - 2) / 2 = 32766 余 1

使用 utf-8 創建

    mysql>     CREATE TABLE `str_test` (
    ->         `id`  tinyint(1)  NOT NULL,
    ->         `name_chn` varchar(21845) NOT NULL
    ->     ) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=utf8
    -> ;
    ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
    mysql>     CREATE TABLE `str_test` (
    ->         `id`  tinyint(1)  NOT NULL,
    ->         `name_chn` varchar(21844) NOT NULL
    ->     ) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=utf8
    ->
    ->
    -> ;
    Query OK, 0 rows affected (0.06 sec)

使用gbk創建

當存儲長度為 32768 失敗~

    mysql>     CREATE TABLE `str_test` (
    ->         `id`  tinyint(1)  NOT NULL,
    ->         `name_chn` varchar(32768) NOT NULL
    ->     ) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=gbk
    -> ;
ERROR 1074 (42000): Column length too big for column 'name_chn' (max = 32767); use BLOB or TEXT instead

當存儲長度為 32767 失敗~

mysql>     CREATE TABLE `str_test` (                                                                                                 ->         `id`  tinyint(1)  NOT NULL,
    ->         `name_chn` varchar(32767) NOT NULL
    ->     ) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=gbk
    -> ;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

當存儲長度為 32766 成功~

mysql>     CREATE TABLE `str_test` (
    ->         `id`  tinyint(1)  NOT NULL,
    ->         `name_chn` varchar(32766) NOT NULL
    ->     ) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=gbk
    -> ;
Query OK, 0 rows affected (0.03 sec)

smallint 用兩個字節存儲,所以

2[smallint] + 32766 * 2[varchar存儲長度] + 2[2個字節來存長度] > 65535

所以失敗~

 mysql>     CREATE TABLE `str_test` (
     ->         `id`  smallint(1)  NOT NULL,
     ->         `name_chn` varchar(32766) NOT NULL
     ->     ) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=gbk
     -> ;
 ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
七、數值類型所占的字節
類型 所占字節
int 4 字節
smallint 2 字節
tinyint 1 字節
decimal 變長

官方關于decimal 的描述如下

Values for DECIMAL (and NUMERIC) columns are represented using a binary format that packs nine decimal (base 10) digits into four bytes.
Storage for the integer and fractional parts of each value are determined separately.
Each multiple of nine digits requires four bytes, and the “leftover” digits require some fraction of four bytes.
The storage required for excess digits is given by the following table.

翻譯為中文

使用二進制格式將9個十進制(基于10)數壓縮為4個字節來表示DECIMAL列值。

每個值的整數和分數部分的存儲分別確定。
每個9位數的倍數需要4個字節,并且“剩余的”位需要4個字節的一部分。
下表給出了超出位數的存儲需求:

Leftover Digits Number Of Bytes
0 0
1 1
2 1
3 2
4 2
5 3
6 3
7 4
8 4

那:decimal(10,2)占幾個字節?

1、首先 10 指的是整數與小數部分的總長度, 2指的是小數部分的長度。那么整數部分就只有 10 - 2 = 8 位

2、因為整數與小數的存儲市各自獨立確定的,所以他們各自所占用空間的綜合就是所占的總空間了。

3、對表可知,整數部分8位占了4個字節,小數部分2位占了1個字節,所以decimal(10,2)總共占了 4 + 1 = 5 個字節。

4、decimal(6,2) 整數部分(6 - 2 = 4) 位占2字節,小數部分2位占1字節,總共占3字節。

八、總結

varchar 字段是將實際內容單獨存儲在聚簇索引之外,內容開頭用1到2個字節表示實際長度(長度超過255時需要2個字節),因此最大長度不能超過65535。

  • UTF-8:一個漢字 = 3個字節,英文是一個字節
  • GBK: 一個漢字 = 2個字節,英文是一個字節

utf-8狀態下,漢字最多可以存 21844個字符串, 英文也為 21844個字符串。

gbk狀態下,漢字最多可以存32766個字符串,英文也為21844個字符串。

參考

mysql utf8mb4與emoji表情
關于GBK、GB2312、UTF8
阿里云 Rails 項目調整 RDS MySQL 編碼為 utf8mb4 的詳細步驟
MySQL下varchar類型最大長度是多少

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • 編碼問題一直困擾著開發人員,尤其在 Java 中更加明顯,因為 Java 是跨平臺語言,不同平臺之間編碼之間的切換...
    x360閱讀 2,498評論 1 20
  • MySQL數據庫對象與應用 2.1-MySQL數據類型 庫建立好之后基本不動,和我們接觸最頻繁的是表. 建表就是聲...
    極客圈閱讀 2,167評論 0 8
  • 2016悄然過去,時間就這么流淌著,感謝給我這個機會總結自己,自己想想這一年還是有些收獲的。 1. 一個白白胖胖的...
    叁一叁閱讀 234評論 4 3
  • 一片金黃色的鳥 在藍天里翱翔 你的眼眸最是深情 鐵窗冰寒禁錮我的雙翼 你展翅對我說 只要你愿意轉身 或者我們也時刻...
    深林小屋閱讀 619評論 0 1
  • 女神應付屌絲常用語:哦,是嗎,一般,還行,呵呵、在洗澡、滾。
    迎刃閱讀 1,269評論 1 2