MySQL中varchar最大長度是多少?

一. varchar存儲規則:html

4.0版本如下,varchar(20),指的是20字節,若是存放UTF8漢字時,只能存6個(每一個漢字3字節) 
5.0版本以上,varchar(20),指的是20字符,不管存放的是數字、字母仍是UTF8漢字(每一個漢字3字節),均可以存放20個,最大大小是65532字節 
 

二. varchar和char 的區別:mysql

char是一種固定長度的類型,varchar則是一種可變長度的類型,它們的區別是: char(M)類型的數據列裏,每一個值都佔用M個字節,若是某個長度小於M,MySQL就會在它的右邊用空格字符補足.(在檢索操做中那些填補出來的空格字符將被去掉)在varchar(M)類型的數據列裏,每一個值只佔用恰好夠用的字節再加上一個用來記錄其長度的字節(即總長度爲L+1字節). sql

在MySQL中用來判斷是否須要進行對據列類型轉換的規則post

一、在一個數據表裏,若是每個數據列的長度都是固定的,那麼每個數據行的長度也將是固定的.編碼

二、只要數據表裏有一個數據列的長度的可變的,那麼各數據行的長度都是可變的.spa

三、若是某個數據表裏的數據行的長度是可變的,那麼,爲了節約存儲空間,MySQL會把這個數據表裏的固定長度類型的數據列轉換爲相應的可變長度類型.例外:長度小於4個字符的char數據列不會被轉換爲varchar類型
 
 
 ps :被問到一個問題:MySQL中varchar最大長度是多少?這不是一個固定的數字。本文簡要說明一下限制規則。
 

一、限制規則指針

字段的限制在字段定義的時候有如下規則:code

a) 存儲限制orm

varchar最多能存儲65535個字節的數據。varchar 的最大長度受限於最大行長度(max row size,65535bytes)。65535並非一個很精確的上限,能夠繼續縮小這個上限。65535個字節包括全部字段的長度,變長字段的長度標識(每一個變長字段額外使用1或者2個字節記錄實際數據長度)、NULL標識位的累計。
 

NULL標識位,若是varchar字段定義中帶有default null容許列空,則須要須要1bit來標識,每8個bits的標識組成一個字段。一張表中存在N個varchar字段,那麼須要(N+7)/8 (取整)bytes存儲全部的NULL標識位。htm

若是數據表只有一個varchar字段且該字段DEFAULT NULL, 那麼該varchar字段的最大長度爲65532個字節,即65535-2-1=65532 byte。
mysql> create table t1 ( name varchar(65532) default null)charset=latin1; Query OK, 0 rows affected (0.09 sec) mysql> 
mysql> create table t2 ( name varchar(65533) default null)charset=latin1; ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs mysql> 

能夠看見當設置長度爲65533時,已經超過行最大長度,咱們能夠計算一下,行最大長度是65535字節。上面t2表name字段使用varchar(65533),字符集是latin1,佔用1個字節。還有默認爲空,那麼還有null標識位,( 1 + 7 ) / 8 =1,因此null標識位佔用1個字節。如今咱們來看看,65533 + 1 + 2=65536字節,已經大於行最大長度。這裏2字節怎麼來的???由於varchar類型存儲變長字段的字符類型,與char類型不一樣的是,其存儲時須要在前綴長度列表加上實際存儲的字符,當存儲的字符串長度小於255字節時,其須要1字節的空間,當大於255字節時,須要2字節的空間。

若是數據表只有一個varchar字段且該字段NOT NULL,那麼該varchar字段的最大長度爲65533個字節,即65535-2=65533byte
mysql> create table t2 ( name varchar(65533) not null) charset=latin1; Query OK, 0 rows affected (0.03 sec) mysql> 
mysql> create table t3 ( name varchar(65534) not null) charset=latin1; ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs mysql> 
b) 編 碼長度限制

字符類型若爲gbk,每一個字符最多佔2個字節,最大長度不能超過32766;

字符類型若爲utf8,每一個字符最多佔3個字節,最大長度不能超過21845。

若定義的時候超過上述限制,則varchar字段會被強行轉爲text類型,併產生warning。
 

c) 行長度限制

致使實際應用中varchar長度限制的是一個行定義的長度。 MySQL要求一個行的定義長度不能超過65535。若定義的表長度超過這個值,則提示

ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs。
 

二、計算例子

舉兩個例說明一下實際長度的計算。

a)  若一個表只有一個varchar類型,如定義爲

create table t4(c varchar(N)) charset=gbk;

則此處N的最大值爲(65535-1-2)/2= 32766。

減1的緣由是實際行存儲從第二個字節開始;

減2的緣由是varchar頭部的2個字節表示長度;

除2的緣由是字符編碼是gbk。
 

b) 若一個表定義爲

create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;

則此處N的最大值爲 (65535-1-2-4-30*3)/3=21812

減1和減2與上例相同;

減4的緣由是int類型的c佔4個字節;

減30*3的緣由是char(30)佔用90個字節,編碼是utf8。
 
若是被varchar超過上述的b規則,被強轉成text類型,則每一個字段佔用定義長度爲11字節,固然這已經不是varchar了。
 
則此處N的最大值爲 (65535-1-2-4-30*3)/3=21812,例子以下:
mysql> create table t4(c int, c2 char(30), c3 varchar(21812)) charset=utf8; Query OK, 0 rows affected (0.05 sec) mysql> 
mysql> create table t5(c int, c2 char(30), c3 varchar(21813)) charset=utf8; ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs mysql> 

 

最後讓咱們來看一個例子

複製代碼
CREATE TABLE t6 ( id int, a VARCHAR(100) DEFAULT NULL, b VARCHAR(100) DEFAULT NULL, c VARCHAR(100) DEFAULT NULL, d VARCHAR(100) DEFAULT NULL, e VARCHAR(100) DEFAULT NULL, f VARCHAR(100) DEFAULT NULL, g VARCHAR(100) DEFAULT NULL, h VARCHAR(100) DEFAULT NULL, i VARCHAR(N) DEFAULT NULL ) CHARSET=utf8; 
複製代碼

那麼上面這條語句中的varchar(N)的最大值是多少呢?

讓咱們來計算一下

每一個NULL字段用1bit標識,10個字段都是default null,那麼須要用(10+7)/8bit = 2 bytes存儲NULL標識位。int佔用4個 byte。

(65535 - 1 - 2*8  -4 - 100*3*8 -2)/3=21037

mysql> CREATE TABLE t6 ( id int, a VARCHAR(100) DEFAULT NULL, b VARCHAR(100) DEFAULT NULL, c VARCHAR(100) DEFAULT NULL, d VARCHAR(100) DEFAULT NULL, e VARCHAR(100) DEFAULT NULL, f VARCHAR(100) DEFAULT NULL, g VARCHAR(100) DEFAULT NULL, h VARCHAR(100) DEFAULT NULL, i VARCHAR(21037) DEFAULT NULL ) CHARSET=utf8; Query OK, 0 rows affected (0.01 sec) mysql> 
mysql> CREATE TABLE t7 ( id int, a VARCHAR(100) DEFAULT NULL, b VARCHAR(100) DEFAULT NULL, c VARCHAR(100) DEFAULT NULL, d VARCHAR(100) DEFAULT NULL, e VARCHAR(100) DEFAULT NULL, f VARCHAR(100) DEFAULT NULL, g VARCHAR(100) DEFAULT NULL, h VARCHAR(100) DEFAULT NULL, i VARCHAR(21038) DEFAULT NULL ) CHARSET=utf8; ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs mysql> 

 能夠看見多一個字符都報錯了。

varchar到底能存多少個字符?這與使用的字符集相關,latin一、gbk、utf8編碼存放一個字符分別須要佔一、二、3個字節。

 

三、varchar物理存儲

在物理存儲上,varchar使用1到2個額外的字節表示實際存儲的字符串長度(bytes)。若是列的最大長度小於256個字節,用一個字節表示(標識)。若是最大長度大於等於256,使用兩個字節。

當選擇的字符集爲latin1,一個字符佔用一個byte

varchar(255)存儲一個字符,一共使用2個bytes物理空間存儲數據實際數據長度和數據值。

varchar(256)存儲一個字符,使用2 bytes表示實際數據長度,一共須要3 bytes物理存儲空間。

varchar對於不一樣的RDBMS引擎,有不通的物理存儲方式,雖然有統一的邏輯意義。對於mysql的不一樣存儲引擎,其實現方法與數據的物理存放方式也不一樣。

四、InnoDB中的varchar

InnoDB中varchar的物理存儲方式與InnoDB使用的innodb_file_format有關。早期的innodb_file_forma使用的Antelope文件格式,支持redundant和compact兩種row_format。從5.5開始或者InnoDB1.1,可使用一種新的file format,Barracuda。Barracuda兼容Redundant,另外還支持dynamic和compressed兩種row_format.

當innodb_file_format=Antelope,ROW_FORMAT=REDUNDANT 或者COMPACT。

innodb的彙集索引(cluster index)僅僅存儲varchar、text、blob字段的前768個字節,多餘的字節存儲在一個獨立的overflow page中,這個列也被稱做off-page。768個字節前綴後面緊跟着20字節指針,指向overflow pages的位置。

另外,在innodb_file_format=Antelope狀況下,InnoDB中最多能存儲10個大字段(須要使用off-page存儲)。innodbd的默認page size爲16KB,InnoDB單行的長度不能超過16k/2=8k個字節,(768+20)*10 < 8k。

當innodb_file_format=Barracuda, ROW_FORMAT=DYNAMIC 或者 COMPRESSED

innodb中全部的varchar、text、blob字段數據是否徹底off-page存儲,根據該字段的長度和整行的總長度而定。對off-page存儲的列,cluster index中僅僅存儲20字節的指針,指向實際的overflow page存儲位置。若是單行的長度太大而不能徹底適配cluster index page,innodb將會選擇最長的列做爲off-page存儲,直到行的長度可以適配cluster index page。

五、MyISAM中的varchar

對於MyISAM引擎,varchar字段全部數據存儲在數據行內(in-line)。myisam表的row_format也影響到varchar的物理存儲行爲。

MyISAM的row_format能夠經過create或者alter sql語句設爲fixed和dynamic。另外能夠經過myisampack生成row_format=compresse的存儲格式。

當myisam表中不存在text或者blob類型的字段,那麼能夠把row_format設置爲fixed(也能夠爲dynamic),不然只能爲dynamic。

當表中存在varchar字段的時候,row_format能夠設定爲fixed或者dynamic。使用row_format=fixed存儲varchar字段數據,浪費存儲空間,varchar此時會定長存儲。row_format爲fixed和dynamic,varchar的物理實現方式也不一樣(能夠查看源代碼文件field.h和field.cc),於是myisam的row_format在fixed和dynamic之間發生轉換的時候,varchar字段的物理存儲方式也將會發生變化。

 

參考資料:

http://dev.mysql.com/doc/refman/5.5/en/column-count-limit.html

<<MySQL技術內幕--InnoDB引擎第二版>>

做者:Atlas

出處:Atlas的博客 http://www.cnblogs.com/gomysql

您的支持是對博主最大的鼓勵,感謝您的認真閱讀。本文版權歸做者全部,歡迎轉載,但請保留該聲明。若是您須要技術支持,本人亦提供有償服務。

相關文章
相關標籤/搜索